iOS 13 UIActivityViewControllerは、前のVC画像の保存後に自動的に表示します
「画像をライブラリに保存」機能を実装してから現在のビューコントローラーに戻そうとしていますが、新しいiOS 13では現在のビューコントローラーを表示したビューコントローラーに戻ります。
PHPhotoLibrary.requestAuthorization({(_ status: PHAuthorizationStatus) -> Void in })
let shareItems: Array = [newImg,"Hello"] as [Any]
let activityController = UIActivityViewController(activityItems: shareItems, applicationActivities: nil)
if UIDevice.current.userInterfaceIdiom == .pad {
activityController.popoverPresentationController?.sourceView = saveButton
}
present(activityController, animated: true)
@KDPのソリューションのSwiftバージョン:
let fakeViewController = TransparentViewController()
fakeViewController.modalPresentationStyle = .overFullScreen
activityViewController.completionWithItemsHandler = { [weak fakeViewController] _, _, _, _ in
if let presentingViewController = fakeViewController?.presentingViewController {
presentingViewController.dismiss(animated: false, completion: nil)
} else {
fakeViewController?.dismiss(animated: false, completion: nil)
}
}
present(fakeViewController, animated: true) { [weak fakeViewController] in
fakeViewController?.present(activityViewController, animated: true, completion: nil)
}
fakeViewController
は、アクティビティの完了によって却下されるか、完了時に却下する必要があります。
次のサルのパッチを生成しました(iOS 13.1.2で確認済み)
- (void)export {
//
// ... Generate Your Activity Items ...
//
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems
applicationActivities:nil
completeBlock:^(NSError *activityError, BOOL completed) {
// Swizzling Dismiss Method
[[self class] switchInstanceMethodFrom:@selector(dismissViewControllerAnimated:completion:) To:@selector(lockedDismissViewControllerAnimated:completion:)];
}
];
// Swizzling Dismiss Method
[[self class] switchInstanceMethodFrom:@selector(dismissViewControllerAnimated:completion:) To:@selector(lockedDismissViewControllerAnimated:completion:)];
[self presentViewController:activityViewController animated:YES completion:nil];
}
- (void)lockedDismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion {
if ([self presentedViewController]) {
[self lockedDismissViewControllerAnimated:flag completion:completion];
}
}
// from http://qiita.com/paming/items/25eaf89e4f448ab05752
+(void)switchInstanceMethodFrom:(SEL)from To:(SEL)to
{
Method fromMethod = class_getInstanceMethod(self,from);
Method toMethod = class_getInstanceMethod(self,to );
method_exchangeImplementations(fromMethod, toMethod);
}
ここでは、このバグを回避する方法を示します。フェイクビューコントローラーを作成し、現在のスタックにプッシュします。 UIActivityTypeSaveToCameraRollはスタックのトップビューコントローラーを閉じますが、他のオプションは閉じないようです。アクティビティタイプが完了しておらず、UIActivityTypeSaveToCameraRollの場合は、完了ブロックで偽のビューコントローラーを閉じるようにします。
typeof(self) __weak weakSelf = self;
[self.activityViewController setCompletionHandler:^(NSString *activityType, BOOL completed) {
if (activityType== UIActivityTypeSaveToCameraRoll && completed){
weakSelf.activityViewController = nil;
}
else{
[weakSelf dismissViewControllerAnimated:NO completion:nil];
weakSelf.activityViewController = nil;
}
}];
UIViewController *fakeVC=[[UIViewController alloc] init];
[self presentViewController:fakeVC animated:NO completion:^{
[fakeVC presentViewController:self.activityViewController animated:YES completion:nil];
}];
- (UIWindow *)displayWindow
{
if (!_displayWindow)
{
_displayWindow = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
_displayWindow.rootViewController = [[UIViewController alloc] init];
}
return _displayWindow;
}
- (void)showActivityController
{
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[] applicationActivities:nil];
activityViewController.completionWithItemsHandler = ^(UIActivityType __nullable activityType, BOOL completed, NSArray * __nullable returnedItems, NSError * __nullable activityError)
{
[UIApplication.sharedApplication.delegate.window makeKeyAndVisible];
};
[self.displayWindow makeKeyAndVisible];
[self.displayWindow.rootViewController presentViewController:activityViewController animated:true completion:nil];
}
_displayWindow
は強い参照です。
ルートビューコントローラーを現在のウィンドウに設定することでこの問題を解決しましたが、なぜ現在のビューコントローラーが閉じられるのかわかりません。 iOS 13で新しいビューコントローラーを表示しているときに、カードスタックアップスタイルに表示され、UIActivityControllerで[画像を保存]を選択すると、現在のビューコントローラー(カード)が非表示になり、前のビューコントローラーが表示されます。