繁体   English   中英

对子类UINavigationController使用自定义iOS 7过渡有时会导致黑屏

[英]Using custom iOS 7 transition with subclassed UINavigationController occasionally results in black screen

我将一个UINavigationController子类化为我的应用程序的主根控制器。 视图控制器的目的是提供一个自定义的启动屏幕,该屏幕允许从(右到左)的滑动操作进入主应用程序。 自定义过渡会在滑动过程中淡化初始视图,并在下面显示主应用程序( UITabBarController )。 我的大部分代码都遵循关于iOS7中自定义视图控制器转换的objc.io文章: http ://www.objc.io/issue-5/view-controller-transitions.html。

一切似乎都按预期进行。 但是,很少有我收到有关启动画面消失而不是主画面出现的黑屏的报告。 我一直无法重现该行为。 这是代码:

首先,在自定义应用程序委托中设置主根视图控制器:

- (void)applicationDidFinishLaunching:(UIApplication *)application 
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.rootViewController = [[CustomRootViewController alloc] initWithNavigationBarClass:nil toolbarClass:nil];
    self.window.rootViewController = self.rootViewController;
    [self.window makeKeyAndVisible];
}

CustomRootViewController重要部分(请注意,我隐藏了导航栏):

- (instancetype) initWithNavigationBarClass:(Class)navigationBarClass toolbarClass:(Class)toolbarClass
{
    self = [super initWithNavigationBarClass:navigationBarClass toolbarClass:toolbarClass];
    if (self) {
        self.navigationBarHidden = YES;
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.delegate = self;

    // This is the main UI for the app
    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
    CustomTabBarControllerViewController *mainViewController = [mainStoryboard instantiateInitialViewController];
    self.mainViewController = mainViewController;

    UIStoryboard *splashStoryboard = [UIStoryboard storyboardWithName:@"Splash" bundle:[NSBundle mainBundle]];
    SplashViewController *splashViewController = [splashStoryboard instantiateInitialViewController];
    self.splashViewController = splashViewController;

    // Initialize the navigation controller to have the main app sitting under the splash screen
    self.viewControllers = @[self.mainViewController, self.splashViewController];
}

// In the public interface, called from the Splash screen when the user can perform the action
- (void)allowSwipeToDismiss
{
    UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    panGestureRecognizer.delegate = self;
    [self.view addGestureRecognizer:panGestureRecognizer];
}

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                  animationControllerForOperation:(UINavigationControllerOperation)operation
                                               fromViewController:(UIViewController *)fromVC
                                                 toViewController:(UIViewController *)toVC
{
    if (operation == UINavigationControllerOperationPop) {
        return [[CustomRootViewControllerAnimator alloc ] init];
    }

    return nil;
}

- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                         interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController
{
    return self.interactiveController;
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    // Only enable swiping when on the Swipe To Enter screen
    // After we are in the main app, we don't want this gesture recognizer interfering with the rest of the app
    if (self.topViewController == self.splashViewController) {
        return true;
    } else {
        return false;
    }
}

- (void)handlePan:(UIPanGestureRecognizer *)recognizer
{
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        self.interactiveController = [[UIPercentDrivenInteractiveTransition alloc] init];
        [self popViewControllerAnimated:YES];
    } else if (recognizer.state == UIGestureRecognizerStateChanged) {
        CGPoint translation = [recognizer translationInView:self.view];
        CGFloat viewWidth = self.view.bounds.size.width;
        CGFloat percentDone = -translation.x / viewWidth;
        [self.interactiveController updateInteractiveTransition:percentDone];
    } else if (recognizer.state == UIGestureRecognizerStateEnded) {
        if (self.interactiveController.percentComplete < 0.5) {
            [self.interactiveController cancelInteractiveTransition];
        } else {
            [self.interactiveController finishInteractiveTransition];
        }
        self.interactiveController = nil;
    }
}

这是我的自定义UINavigationController返回的CustomRootViewControllerAnimator的代码:

@implementation CustomRootViewControllerAnimator

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
    return 1;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

    [[transitionContext containerView] insertSubview:toViewController.view
                                        belowSubview:fromViewController.view];

    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
        CGFloat screenWidth = [[UIScreen mainScreen] bounds].size.width;
        fromViewController.view.transform = CGAffineTransformMakeTranslation(-screenWidth, 0);
        fromViewController.view.alpha = 0;
    } completion:^(BOOL finished) {
        fromViewController.view.transform = CGAffineTransformIdentity;
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
    }];
}

@end

终于能够重现该问题,但仅在iOS 7.0中。 通过启动交互式过渡,然后取消它,我可以在过渡的下一个开始时获得黑屏。 在完成块中,我需要将fromViewController的alpha值设置回1。同样,这仅在iOS 7.0中是必需的。 在7.1中不会发生。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM