2

我尝试制作一个自定义 segue 来模拟来自 iOS6 的旧 segue 推送,因为新的推送 segue 不适用于我的应用程序。

-(void)perform {

    UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
    UIViewController *destinationController = (UIViewController*)[self destinationViewController];

    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



    [sourceViewController.navigationController.view.layer addAnimation:transition
                                                                forKey:kCATransition];

    [sourceViewController.navigationController pushViewController:destinationController animated:NO];

}

一切都嵌入在导航控制器中。我已将延伸边缘标记为“在顶部栏下方”和“在底部栏下方”。而且我在两个视图控制器(源和目标)中都有视图的自定义背景颜色。在这两个视图控制器之间的过渡期间,导航栏开始在白色和两个视图控制器的自定义背景颜色之间闪烁。知道为什么吗?

4

1 回答 1

4

您的代码中的问题是:

当您触发该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

于 2013-12-04T10:40:17.570 回答