[英]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.