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

Rob*_*Rob 62 uinavigationcontroller autolayout ios7 custom-transition

精简版:

当与自定义转换和UINavigationControlleriOS7 结合使用时,我遇到了自动布局顶部布局指南的问题.具体而言,顶级布局指南和文本视图之间的约束不受尊重.有没有人遇到过这个问题?


长版:

我有一个场景明确定义了约束(即顶部,底部,左侧和右侧),呈现如下视图:

对

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

错误

使用自定义转换时,导航控制器的"顶部布局指南"似乎变得混乱.其余约束正确应用.如果我旋转设备并再次旋转它,一切都会突然正确呈现,所以看起来并不是没有正确定义约束.同样,当我关闭自定义转换时,视图会正确呈现.

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

(lldb) po [[UIWindow keyWindow] _autolayoutTrace]
Run Code Online (Sandbox Code Playgroud)

但是每当我看到它们时,这些布局指南总是被报告为含糊不清,即使我已经确保没有遗漏约束(我已经习惯性地选择视图控制器并选择"为视图控制器添加缺少的约束"或选择全部控制和为他们做同样的事情).

在如何我正是这样做的过渡方面,我指定符合对象UIViewControllerAnimatedTransitioninganimationControllerForOperation方法:

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

    return nil;
}
Run Code Online (Sandbox Code Playgroud)

@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
Run Code Online (Sandbox Code Playgroud)

我也完成了上面的描述,设置frame了视图而不是transform结果,结果相同.

我也试过手动确保通过调用重新应用约束layoutIfNeeded.我也试过setNeedsUpdateConstraints,setNeedsLayout

最重要的是,有没有人成功结婚导航控制器的自定义过渡与使用顶部布局指南的约束?

小智 28

通过添加以下行来管理解决我的问题:

toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController];
Run Code Online (Sandbox Code Playgroud)

至:

- (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]];
    }];

}
Run Code Online (Sandbox Code Playgroud)

来自Apple的[finalFrameForViewController]文档:https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewControllerContextTransitioning_protocol/#//apple_ref/occ/intfm/UIViewControllerContextTransitioning/finalFrameForViewController:

  • 这是唯一适合我的!`[transitionContext finalFrameForViewController:toVC]`已经有了正确的topLayoutGuide.你让我今天一整天都感觉很好!谢谢! (4认同)
  • 真棒!这是问题的唯一有效答案!其余的只是非常脏的黑客!谢谢! (4认同)

Ale*_*lav 15

我通过修复高度约束来解决这个问题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 ...
}
Run Code Online (Sandbox Code Playgroud)


Jas*_*rus 10

我遇到了同样的问题.把它放在我的toViewController的viewDidLoad中真的帮了我:

self.edgesForExtendedLayout = UIRectEdgeNone;
Run Code Online (Sandbox Code Playgroud)

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

  • 嘿抢劫,你和Apple一起提出雷达吗? (2认同)

小智 5

只需将以下代码放入viewDidLoad

self.extendedLayoutIncludesOpaqueBars = YES;
Run Code Online (Sandbox Code Playgroud)