简体   繁体   中英

Rotating whilst pushing a view controller onto a navigation controller does not correctly size pushed view controller

I'm seeing a really weird issue; pushing a view controller into a navigation controller just as the user rotates the device causes the pushed view controller to not autolayout itself to the navigation controller.

Here's a demonstration where a button press fires the pushViewController:

[ 1]

First you can see the push working as expected (no rotation), then messing up (with rotation) on a push and finally messing up (with rotation) on a pop.

I purposefully made the simplest project I could think of to test this, so the storyboard is a viewcontroller with a button in a navigation controller and the entirety of the code is:

- (void)didTapButton:(id)sender
{
    UIViewController *viewController = [[UIViewController alloc] init];
    viewController.view.backgroundColor = [UIColor whiteColor];

    [self.navigationController pushViewController:viewController animated:YES];
}

I find it hard to believe I've hit a hitherto unnoticed bug in iOS11 and 12 (doesn't occur in 10) but I'm truly at a loss to see what I could be doing wrong here if it's my fault in some way.

Anyone seen this before or have suggestions what I'm missing here?

My guess would be that it's some sort of race condition to do with pushing while transitioning to a different size. Probably the updateConstraints/needsLayout flag is NO when the transition to the new size is complete (ie it already thinks it's fully finished laying out it's view after the push is complete but the rotation hasn't completed). I would consider this an Apple Bug and would report it if you haven't already.

As a workaround you could use a subclass of UINavigationController and implement viewWillTransitionToSize:withTransitionCoordinator: then if needed throw an extra [self.view setNeedsLayout] or [self.view setNeedsUpdateConstraints] in the completion block of coordinator animateAlongsideTransition:completion:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
    } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
        UIView *topView = [self.topViewController view];
        // we should only need an additional layout if the topView's size doesn't match the size
        // we're transitioning to (otherwise it should have already beend layed out properly)
        BOOL needsAdditionalLayout = topView && CGSizeEqualToSize(topView.frame.size, size) == NO;
        if (needsAdditionalLayout) {
            // either of these two should do the trick
            [self.view setNeedsUpdateConstraints];
            // [self.view setNeedsLayout];
        }
    }];
}

This seemed to properly resize the views after the transition to size completed.

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