精简版:
当与自定义转换和UINavigationController
iOS7 结合使用时,我遇到了自动布局顶部布局指南的问题.具体而言,顶级布局指南和文本视图之间的约束不受尊重.有没有人遇到过这个问题?
长版:
我有一个场景明确定义了约束(即顶部,底部,左侧和右侧),呈现如下视图:
但是当我在导航控制器上使用自定义转换时,顶部布局指南的顶部约束似乎关闭,它呈现如下,好像顶部布局指南位于屏幕顶部,而不是底部导航控制器:
使用自定义转换时,导航控制器的"顶部布局指南"似乎变得混乱.其余约束正确应用.如果我旋转设备并再次旋转它,一切都会突然正确呈现,所以看起来并不是没有正确定义约束.同样,当我关闭自定义转换时,视图会正确呈现.
话虽如此,当我运行时_autolayoutTrace
报告UILayoutGuide
对象受到影响AMBIGUOUS LAYOUT
:
(lldb) po [[UIWindow keyWindow] _autolayoutTrace]
但是每当我看到它们时,这些布局指南总是被报告为含糊不清,即使我已经确保没有遗漏约束(我已经习惯性地选择视图控制器并选择"为视图控制器添加缺少的约束"或选择全部控制和为他们做同样的事情).
在如何我正是这样做的过渡方面,我指定符合对象UIViewControllerAnimatedTransitioning
的animationControllerForOperation
方法:
- (id)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)transitionContext { return 0.5; } - (void)animateTransition:(id )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
.我也试过setNeedsUpdateConstraints
,setNeedsLayout
等
最重要的是,有没有人成功结婚导航控制器的自定义过渡与使用顶部布局指南的约束?
通过添加以下行来管理解决我的问题:
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]]; }]; }
来自Apple的[finalFrameForViewController]文档:https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewControllerContextTransitioning_protocol/#//apple_ref/occ/intfm/UIViewControllerContextTransitioning/finalFrameForViewController:
只需将以下代码放入viewDidLoad
self.extendedLayoutIncludesOpaqueBars = YES;
我遇到了同样的问题.把它放在我的toViewController的viewDidLoad中真的帮了我:
self.edgesForExtendedLayout = UIRectEdgeNone;
这并没有解决我的所有问题,我仍然在寻找更好的方法,但这确实使它更容易一些.
我通过修复高度约束来解决这个问题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 ... }