使用带有子类UINavigationController的自定义iOS 7过渡偶尔会导致黑屏

时间:2014-08-26 18:58:47

标签: ios objective-c iphone ios7

我正在继承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

1 个答案:

答案 0 :(得分:0)

终于能够复制问题,但仅限于iOS 7.0。通过启动交互式转换,然后取消它,我能够在下一次转换开始时获得黑屏。在完成块中,我需要将fromViewController的alpha值设置回1.再次,这仅在iOS 7.0中是必需的。它不会发生在7.1。