コードの問題は次のとおりです。
pushViewController
メソッドをトリガーするsourceViewController
と、 がナビゲーション スタックからすぐに削除され、 が表示されdestinationViewController
ます。これにより、アニメーションに問題が発生します (この問題は iOS 6 でも存在し、別の問題である「黒いフェード」を引き起こします)。それでも使用したい場合pushViewController
(ナビゲーション ロジックを再構築する必要がないため簡単です)、Apple の提案に従って実行する必要があります。
アニメーションの実行方法に関係なく、アニメーションの最後に、目的のビュー コントローラー (およびそのビュー) を適切な場所にインストールして、イベントを処理できるようにする必要があります。たとえば、カスタム モーダル トランジションを実装する場合、スナップショット イメージを使用してアニメーションを実行し、最後に presentModalViewController:animated: メソッドを (アニメーションを無効にして) 呼び出して、ソースと宛先の間の適切なモーダル関係を設定します。ビューコントローラー。
スナップショットを使用する必要があります。
ここで、実行メソッドが更新されました:
- (void)perform
{
UIViewController *source = (UIViewController *) self.sourceViewController;
UIViewController *destination = (UIViewController *) self.destinationViewController;
// Swap the snapshot out for the source view controller
UIWindow *window = source.view.window;
UIImageView *screenShot = [[UIImageView alloc] initWithImage:[self screenshot]];
BOOL animsEnabled = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled:NO];
[window addSubview:screenShot];
[UIView setAnimationsEnabled:animsEnabled];
CATransition* transition = [CATransition animation];
transition.duration = 1.5;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
transition.subtype = kCATransitionFromRight; //kCATransitionFromLeft, kCATransitionFromRight, kCATransitionFromTop, kCATransitionFromBottom
[source.navigationController pushViewController:destination animated:NO];
[destination.navigationController.view.layer addAnimation:transition forKey:kCATransition];
[UIView animateWithDuration:1.5f animations:^{
screenShot.frame = CGRectOffset(screenShot.frame, -screenShot.frame.size.width, 0);
} completion:^(BOOL finished) {
[screenShot removeFromSuperview];
}];
}
正しいスクリーンショットを作成するにrenderInContext
は、半透明のバーのぼかしが正しく処理されていないため、単にメソッドを使用するだけでは十分ではありません。別の方法を見つけました(この質問からコピーして貼り付けました)
- (UIImage *)screenshot
{
CGSize imageSize = CGSizeZero;
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UIInterfaceOrientationIsPortrait(orientation)) {
imageSize = [UIScreen mainScreen].bounds.size;
} else {
imageSize = CGSizeMake([UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width);
}
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
for (UIWindow *window in [[UIApplication sharedApplication] windows]) {
CGContextSaveGState(context);
CGContextTranslateCTM(context, window.center.x, window.center.y);
CGContextConcatCTM(context, window.transform);
CGContextTranslateCTM(context, -window.bounds.size.width * window.layer.anchorPoint.x, -window.bounds.size.height * window.layer.anchorPoint.y);
if (orientation == UIInterfaceOrientationLandscapeLeft) {
CGContextRotateCTM(context, M_PI_2);
CGContextTranslateCTM(context, 0, -imageSize.width);
} else if (orientation == UIInterfaceOrientationLandscapeRight) {
CGContextRotateCTM(context, -M_PI_2);
CGContextTranslateCTM(context, -imageSize.height, 0);
} else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
CGContextRotateCTM(context, M_PI);
CGContextTranslateCTM(context, -imageSize.width, -imageSize.height);
}
if ([window respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
[window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
} else {
[window.layer renderInContext:context];
}
CGContextRestoreGState(context);
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
どのように動作するかを示すサンプル プロジェクトを添付します:サンプル プロジェクトへのリンク