您的代码中的问题是:
当您触发该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;
}
I attach a sample project showing how it works: Link to sample project