导航控制器顶部布局指南不符合自定义转换

简洁版本:

在iOS7中与自定义转换和UINavigationController一起使用时,我遇到了自动布局顶部布局指南问题。 具体来说,顶部布局指南和文本视图之间的约束不被遵守。 有没有人遇到过这个问题?


长版本:

我有一个场景明确定义了一个视图,例如:顶部,底部,左侧和右侧:

对

但是当我在导航控制器上使用自定义转换时,顶部布局指南的顶部约束似乎关闭,呈现如下,就好像顶部布局指南位于屏幕的顶部而不是底部的导航控制器:

错误

看起来,使用导航控制器的“顶部布局指南”在使用自定义转换时会变得困惑。 剩下的约束正在正确应用。 如果我旋转设备并再次旋转,一切都会突然呈现正确,所以看起来不是约束没有被正确定义的问题。 同样,当我关闭自定义转换时,视图正确呈现。

话虽如此, _autolayoutTrace报告说, UILayoutGuide对象遭受AMBIGUOUS LAYOUT ,当我运行时:

(lldb) po [[UIWindow keyWindow] _autolayoutTrace]

但是,即使我已经确保没有缺少约束(我已经完成了习惯上选择视图控制器并选择“为视图控制器添加缺少的约束”或选择了全部视图,但这些布局指南在我看到它们时总是被报告为不明确的的控制,并为他们做同样的)。

就我如何精确转换而言,我已经在animationControllerForOperation方法中指定了一个符合UIViewControllerAnimatedTransitioning的对象:

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                  animationControllerForOperation:(UINavigationControllerOperation)operation
                                               fromViewController:(UIViewController*)fromVC
                                                 toViewController:(UIViewController*)toVC
{
    if (operation == UINavigationControllerOperationPush)
        return [[PushAnimator alloc] init];

    return nil;
}

@implementation PushAnimator

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
    return 0.5;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    UIViewController* toViewController   = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

    [[transitionContext containerView] addSubview:toViewController.view];
    CGFloat width = fromViewController.view.frame.size.width;

    toViewController.view.transform = CGAffineTransformMakeTranslation(width, 0);

    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
        fromViewController.view.transform = CGAffineTransformMakeTranslation(-width / 2.0, 0);
        toViewController.view.transform = CGAffineTransformIdentity;
    } completion:^(BOOL finished) {
        fromViewController.view.transform = CGAffineTransformIdentity;
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
    }];
}

@end

我也做了上述的再现,设置视图的frame而不是transform ,结果相同。

我也尝试通过调用layoutIfNeeded手动确保约束被重新应用。 我也尝试了setNeedsUpdateConstraintssetNeedsLayout等。

底线,是否有人成功结婚导航控制器的自定义转换与约束,使用顶级布局指南?


我通过修复topLayoutGuide的高度限制来解决这个问题。 调整edgesForExtendedLayout对我来说不是一种选择,因为我需要目标视图来重叠导航栏,但也能够使用topLayoutGuide布局子视图。

直接检查游戏中的约束条件可以看出,iOS为topLayoutGuide添加了一个高度约束,其值等于导航控制器导航栏的高度。 除了在iOS 7中,使用自定义动画转换离开约束的高度为0.他们在iOS 8中修复了这个问题。

这是我想出的解决这个约束的解决方案(它是在Swift中,但相当于Obj-C中的工作)。 我已经测试过它可以在iOS 7和8上运行。

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    let fromView = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!.view
    let destinationVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    destinationVC.view.frame = transitionContext.finalFrameForViewController(destinationVC)
    let container = transitionContext.containerView()
    container.addSubview(destinationVC.view)

    // Custom transitions break topLayoutGuide in iOS 7, fix its constraint
    if let navController = destinationVC.navigationController {
        for constraint in destinationVC.view.constraints() as [NSLayoutConstraint] {
            if constraint.firstItem === destinationVC.topLayoutGuide
                && constraint.firstAttribute == .Height
                && constraint.secondItem == nil
                && constraint.constant == 0 {
                constraint.constant = navController.navigationBar.frame.height
            }
        }
    }

    // Perform your transition animation here ...
}

通过添加以下代码管理我的问题:

toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController];

至:

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext fromVC:(UIViewController *)fromVC toVC:(UIViewController *)toVC fromView:(UIView *)fromView toView:(UIView *)toView {

    // Add the toView to the container
    UIView* containerView = [transitionContext containerView];
    [containerView addSubview:toView];
    [containerView sendSubviewToBack:toView];


    // animate
    toVC.view.frame = [transitionContext finalFrameForViewController:toVC];
    NSTimeInterval duration = [self transitionDuration:transitionContext];
    [UIView animateWithDuration:duration animations:^{
        fromView.alpha = 0.0;
    } completion:^(BOOL finished) {
        if ([transitionContext transitionWasCancelled]) {
            fromView.alpha = 1.0;
        } else {
            // reset from- view to its original state
            [fromView removeFromSuperview];
            fromView.alpha = 1.0;
        }
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
    }];

}

从苹果公司的文档[finalFrameForViewController]:https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewControllerContextTransitioning_protocol/#//apple_ref/occ/intfm/UIViewControllerContextTransitioning/finalFrameForViewController:


我挣扎于完全相同的问题。 把它放在我的toViewController的viewDidLoad中真的帮了我很大的忙:

self.edgesForExtendedLayout = UIRectEdgeNone;

这并没有解决我所有的问题,我仍然在寻找更好的方法,但这确实使它更容易一些。

链接地址: http://www.djcxy.com/p/68291.html

上一篇: Navigation controller top layout guide not honored with custom transition

下一篇: How to set topLayoutGuide position for child view controller