导航控制器顶部布局指南不符合自定义转换
简洁版本:
在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
手动确保约束被重新应用。 我也尝试了setNeedsUpdateConstraints
, setNeedsLayout
等。
底线,是否有人成功结婚导航控制器的自定义转换与约束,使用顶级布局指南?
我通过修复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