Presenting a UINavigationController in a custom mo

2020-02-26 14:11发布

问题:

I'm trying to present a UINavigationController from a UINavigationController. I'm using the new iOS 7 transitioningDelegate stuff and it's working great.... except the navigation bar starts out tall and then shrinks when the animation is over. I'm assuming it shrinks because the bar doesn't touch the top of the screen, but why does it start out tall? Can I prevent this?

Here's the animation code:

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {

    UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView* containerView = [transitionContext containerView];

    if (toViewController.isBeingPresented) {
        [self presentModalView:toViewController.view fromView:fromViewController.view inContainerView:containerView withTransitionContext:transitionContext];
    } else {
        [self dismissModalView:fromViewController.view fromView:toViewController.view withTransitionContext:transitionContext];
    }
}

- (void)presentModalView:(UIView*)modalView fromView:(UIView*)presentationView inContainerView:(UIView*)containerView withTransitionContext:(id<UIViewControllerContextTransitioning>)transitionContext {
    [containerView addSubview:modalView];
    presentationView.userInteractionEnabled = NO;

    modalView.layer.cornerRadius = 5;
    modalView.clipsToBounds = YES;

    CGRect finalFrame = CGRectInset(presentationView.frame, 10, 20);
    modalView.frame = CGRectOffset(finalFrame, 0, CGRectGetHeight(presentationView.frame));

    [UIView animateWithDuration:animationDuration animations:^{
        modalView.frame = finalFrame;
        presentationView.alpha = 0.2;
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:YES];
    }];
}

回答1:

I have a solution to this problem.

From http://blog.jaredsinclair.com/post/61507315630/wrestling-with-status-bars-and-navigation-bars-on-ios-7, number 4:

UINavigationController will alter the height of its UINavigationBar to either 44 points or 64 points, depending on a rather strange and undocumented set of constraints. If the UINavigationController detects that the top of its view’s frame is visually contiguous with its UIWindow’s top, then it draws its navigation bar with a height of 64 points. If its view’s top is not contiguous with the UIWindow’s top (even if off by only one point), then it draws its navigation bar in the “traditional” way with a height of 44 points. This logic is performed by UINavigationController even if it is several children down inside the view controller hierarchy of your application. There is no way to prevent this behavior.

Your problem, therefore, is that the UINavigationController is detecting that its view's frame is contiguous with the UIWindow's top at the beginning of the animation. This is due to the fact that when you added the modalView as a subview of the containerView, the frame of the modalView is {0,0,0,0}. Because this frame would be visually contiguous with the UIWindow's top, the UINavigationController draws its UINavigationBar with a height of 64 points. When the animation is completed the new frame of the navigation controller is no longer continuous with the windows top, and it draws the navigation bar with a height of 44.

One solution is to add the navigation controller's view to the container view AFTER setting it's frame. Like so,

 - (void)presentModalView:(UIView*)modalView fromView:(UIView*)presentationView inContainerView:(UIView*)containerView withTransitionContext:(id<UIViewControllerContextTransitioning>)transitionContext {
    presentationView.userInteractionEnabled = NO;

    modalView.layer.cornerRadius = 5;
    modalView.clipsToBounds = YES;

    CGRect finalFrame = CGRectInset(presentationView.frame, 10, 20);
    modalView.frame = CGRectOffset(finalFrame, 0, CGRectGetHeight(presentationView.frame));
    [containerView addSubview:modalView];

    [UIView animateWithDuration:animationDuration animations:^{
        modalView.frame = finalFrame;
        presentationView.alpha = 0.2;
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:YES];
    }];
}

That should solve your problem, in that the navigation bar will always be drawn with a height of 44 points throughout the animation. I don't know of a way to keep the height of the navigation bar 64 points, because that would involve fooling the navigation controller into thinking it was contiguous with the top of the window.