简体   繁体   中英

When using [UIViewControllerTransitionCoordinator animateAlongsideTransition:completion:] in a modal presentation, the animation block is not called

I have a UIViewController that is being presented via a modal segue in a storyboard (embedded in a UINavigationController ). I'm trying to animate the keyboard appearance alongside the modal presentation (logic for this is beyond the scope of the question).

I'm using [self.transitionCoordinator animateAlongsideTransition:completion:] in viewWillAppear: to do this but I'm noticing that that the animation block is never being called. So a bit of logging has led me to see that the only time the animation block is called on a newly created modal view controller is during viewDidLoad: .

@implementation MyModalViewController

- (void)viewDidLoad {
    NSLog(@"%s", __PRETTY_FUNCTION__);
    [super viewDidLoad];

    [self.transitionCoordinator animateAlongsideTransition:^ (id <UIViewControllerTransitionCoordinatorContext> context) {
        NSLog(@"%s ANIMATION", __PRETTY_FUNCTION__);
    } completion:^ (id <UIViewControllerTransitionCoordinatorContext> context) {
        NSLog(@"%s COMPLETION", __PRETTY_FUNCTION__);
    }];
}

- (void)viewWillAppear:(BOOL)animated {
    NSLog(@"%s", __PRETTY_FUNCTION__);
    [super viewWillAppear:animated];

    [self.transitionCoordinator animateAlongsideTransition:^ (id <UIViewControllerTransitionCoordinatorContext> context) {
        NSLog(@"%s ANIMATION", __PRETTY_FUNCTION__);
    } completion:^ (id <UIViewControllerTransitionCoordinatorContext> context) {
        NSLog(@"%s COMPLETION", __PRETTY_FUNCTION__);
    }];
}

- (void)viewWillDisappear:(BOOL)animated {
    NSLog(@"%s", __PRETTY_FUNCTION__);
    [super viewWillDisappear:animated];

    [self.transitionCoordinator animateAlongsideTransition:^ (id <UIViewControllerTransitionCoordinatorContext> context) {
        NSLog(@"%s ANIMATION", __PRETTY_FUNCTION__);
    } completion:^ (id <UIViewControllerTransitionCoordinatorContext> context) {
        NSLog(@"%s COMPLETION", __PRETTY_FUNCTION__);
    }];
}

@end

The output of a modal presentation of this controller is:

SampleAnimatedTransition[43690:1768171] -[MyModalViewController viewDidLoad]
SampleAnimatedTransition[43690:1768171] __36-[MyModalViewController viewDidLoad]_block_invoke ANIMATION
SampleAnimatedTransition[43690:1768171] -[MyModalViewController viewWillAppear:]
SampleAnimatedTransition[43690:1768171] __36-[MyModalViewController viewDidLoad]_block_invoke_2 COMPLETION
SampleAnimatedTransition[43690:1768171] __40-[MyModalViewController viewWillAppear:]_block_invoke_2 COMPLETION

but during dismissal the output is:

SampleAnimatedTransition[43690:1768171] -[MyModalViewController viewWillDisappear:]
SampleAnimatedTransition[43690:1768171] __43-[MyModalViewController viewWillDisappear:]_block_invoke ANIMATION
SampleAnimatedTransition[43690:1768171] __43-[MyModalViewController viewWillDisappear:]_block_invoke_2 COMPLETION

Notice how the animation block is not called in viewWillAppear: , and even more annoyingly the animation block from viewDidLoad: is called before viewWillAppear: is called at all.

Can anyone help me get the animation block is viewWillAppear: to be called?

Note that when I push another view controller onto the navigation controller and hit back, the animation block in viewWillAppear: is called.

I made a Sample Project if it helps.

Update

This has been filed as rdar://20171073

You're presenting a UINavigationController . You can animate with that presentation by subclassing UINavigationController and overriding -viewWillAppear: . However, at this point the navigation controller has not yet added its root view controller to the view hierarchy so any animations you set up will not work.

@implementation MyNavigationController
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self.transitionCoordinator animateAlongsideTransition:^ (id <UIViewControllerTransitionCoordinatorContext> context) {
        NSAssert([self.viewControllers[0] superview] != nil, @""); // Fails
    } completion:nil];
}
@end

As it turns out, you can force UINavigationController to set up its view hierarchy by using layoutIfNecessary :

@implemenation MyNavigationController
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self.view layoutIfNeeded];
}
@end

That also takes care of calling -viewWillAppear: on the root view controller at a point that allows you to animate with the modal presentation.

With this hack I'm able to animate along side the modal presentation. It's ugly and I wouldn't use it, but it would at least allow you to test whether your approach at keyboard animation has any merit.

Depending on what you're actually trying to accomplish, you may have more luck creating a custom modal presentation with UIPresentationController .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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