Right To Left Push animation results in corrupted

2019-04-17 08:59发布

I'm subclassing my UINavigationController to perform a push from right to left (not normal behavior) with UIRTLNavigationController.m I've added at the bottom of this question and get these warnings:

 nested push animation can result in corrupted navigation bar
 Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.

I've researched about these errors and found a class that prevents you from receiving them: https://github.com/Plasma/BufferedNavigationController

I've added BufferedNavigationController .h and .m to my project, changed the line in BufferedNavigationController.h to: @interface BufferedNavigationController : UIRTLNavigationController and seted BufferedNavigationController to be my UINavigationController custom subclass in the IB.

Views are still moving from right to left , methods are getting called inside BufferedNavigationController but I'm still get the warnings about nested and ..Navigation Bar subview tree might get corrupted..

Any help would be appreciated.

UIRTLNavigationController.m:

#import "UIRTLNavigationController.h"


@implementation UIRTLNavigationController

- (id)initWithRootViewController:(UIViewController *)rootViewController
{
        self = [super initWithRootViewController:rootViewController];
        if (!self)
                return nil;
        return self;
}

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
        NSLog(@"pushViewController");
        // Add the viewController and a fake controller without animation. Then pop the fake controller with animation.
        UIViewController *fakeController = [[[UIViewController alloc] init] autorelease];
        [super setViewControllers:[[self viewControllers] arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:viewController, fakeController, nil]] animated:NO];
        [super popViewControllerAnimated:animated];
}

- (void)popViewControllerAnimatedStep2:(UIViewController *)viewController
{
        // Push the new top controller with animation
        [super pushViewController:viewController animated:YES];
        // Remove the view that should have been popped
        NSMutableArray *arr = [NSMutableArray arrayWithArray:[self viewControllers]];
        [arr removeObjectAtIndex:[[self viewControllers] count]-2];
        [super setViewControllers:[NSArray arrayWithArray:arr] animated:NO];
}

- (UIViewController *)popViewControllerAnimated:(BOOL)animated
{
        NSLog(@"popViewControllerAnimated");

        if (animated)
        {
                // Save the controller that should be on top after this pop operation
                UIViewController *newTopController = [[self viewControllers] objectAtIndex:[[self viewControllers] count]-2];
                // Remove it from the stack. Leave the view that should be popped on top
                NSMutableArray *arr = [NSMutableArray arrayWithArray:[self viewControllers]];
                [arr removeObjectAtIndex:[[self viewControllers] count]-2];
                [super setViewControllers:[NSArray arrayWithArray:arr] animated:NO];
                // Schedule the next step
                [self performSelector:@selector(popViewControllerAnimatedStep2:) withObject:newTopController afterDelay:0];
                return [arr objectAtIndex:[arr count]-1];
        }
        return [super popViewControllerAnimated:NO];
}

- (void)dealloc {
    [super dealloc];
}


@end

2条回答
神经病院院长
2楼-- · 2019-04-17 09:18

I don't know if you are creating the custom UINavigationController just to perform a custom transition, if you do, there is an easier way to do it. Like the following code

-(void)makeMyCustomAnimation {
      YourDestinationViewController *destinationController = [YourDestinationViewController 
                                                             alloc] initWithNib.....];//add the missing code fot ini

  CATransition* transition = [CATransition animation];
  transition.duration = .25; //you can change this value to fit your needs
  transition.timingFunction = [CAMediaTimingFunction functionWithName: 
                                           kCAMediaTimingFunctionEaseInEaseOut]; 
                                           //kCAMediaTimingFunctionLinear
                                           //kCAMediaTimingFunctionEaseIn
                                           //kCAMediaTimingFunctionEaseOut
                                           //kCAMediaTimingFunctionEaseInEaseOut
                                           //kCAMediaTimingFunctionDefault

   transition.type = kCATransitionPush; //kCATransitionMoveIn;
                                     //kCATransitionPush,  
                                     //kCATransitionReveal
                                     //kCATransitionFade

   transition.subtype = kCATransitionFromRight; 
                       //kCATransitionFromLeft,
                       //kCATransitionFromRight 
                       //kCATransitionFromTop, 
                      //kCATransitionFromBottom

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

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

}

You can change the direction of your transition by changing the subtype value.(I might be set the wrong value of the subtype, I keep mixing them)

Also you can use the same approach for pop-ing the view controller. I

And It can be used if you want to use segues, just create a custom segue and overrode the -(void)perform method by adding the previous code with some additions, you have to get the view controllers with [self sourceViewController]; and [self destinationViewController];

查看更多
Melony?
3楼-- · 2019-04-17 09:32

For me the problem was pushing controllers one after another, that caused several transition animations one after another. This link helped me: https://github.com/Plasma/BufferedNavigationController/blob/master/BufferedNavigationController.m

I got it from this stack overflow answer: iOS: popViewController unexpected behavior

查看更多
登录 后发表回答