[英]Using custom iOS 7 transition with subclassed UINavigationController occasionally results in black screen
I am subclassing a UINavigationController
to serve as the main root controller of my application. 我将一个UINavigationController
子类化为我的应用程序的主根控制器。 The purpose of the view controller is to present a custom splash screen that allows for a swipe action from (right to left) to enter the main application. 视图控制器的目的是提供一个自定义的启动屏幕,该屏幕允许从(右到左)的滑动操作进入主应用程序。 The custom transition fades the splash view during the swipe and reveals the main application underneath (a UITabBarController
). 自定义过渡会在滑动过程中淡化初始视图,并在下面显示主应用程序( UITabBarController
)。 Most of my code is following the objc.io article on custom view controller transitions in iOS7: http://www.objc.io/issue-5/view-controller-transitions.html . 我的大部分代码都遵循关于iOS7中自定义视图控制器转换的objc.io文章: http ://www.objc.io/issue-5/view-controller-transitions.html。
Everything seems to work as expected. 一切似乎都按预期进行。 However, very rarely, I am getting reports of a black screen appearing once the splash screen disappears, instead of the main screen. 但是,很少有我收到有关启动画面消失而不是主画面出现的黑屏的报告。 I have been unable to reproduce the behavior. 我一直无法重现该行为。 Here is the code: 这是代码:
First, setting up the main root view controller in the custom app delegate: 首先,在自定义应用程序委托中设置主根视图控制器:
- (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];
}
Important portions from CustomRootViewController
(note I'm hiding the navigation bar): 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;
}
}
And here is the code for the CustomRootViewControllerAnimator
being returned by my custom UINavigationController: 这是我的自定义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
Was finally able to replicate the problem, but only in iOS 7.0. 终于能够重现该问题,但仅在iOS 7.0中。 By starting the interactive transition, then canceling it, I was able to get the black screen on the next start of the transition. 通过启动交互式过渡,然后取消它,我可以在过渡的下一个开始时获得黑屏。 In the completion block, I needed to set the alpha value of the fromViewController back to 1. Again, this is only necessary in iOS 7.0. 在完成块中,我需要将fromViewController的alpha值设置回1。同样,这仅在iOS 7.0中是必需的。 It does not happen in 7.1. 在7.1中不会发生。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.