Short version:
I am having a problem with auto layout top layout guide when used in conjunction with custom transition and UINavigationController
in iOS7. Specifically, the constraint between the top layout guide and the text view is not being honored. Has anyone encountered this issue?
Long version:
I have a scene which has unambiguously define constraints (i.e. top, bottom, left and right) that renders a view like so:
But when I use this with a custom transition on the navigation controller, the top constraint to the top layout guide seems off and it renders is as follows, as if the top layout guide was at the top of the screen, rather than at the bottom of the navigation controller:
It would appear that the "top layout guide" with the navigation controller is getting confused when employing the custom transition. The rest of the constraints are being applied correctly. And if I rotate the device and rotate it again, everything is suddenly rendered correctly, so it does not appear to be not a matter that the constraints are not defined properly. Likewise, when I turn off my custom transition, the views render correctly.
Having said that, _autolayoutTrace
is reporting that the UILayoutGuide
objects suffer from AMBIGUOUS LAYOUT
, when I run:
(lldb) po [[UIWindow keyWindow] _autolayoutTrace]
But those layout guides are always reported as ambiguous whenever I look at them even though I've ensured that there are no missing constraints (I've done the customary selecting of view controller and choosing "Add missing constraints for view controller" or selecting all of the controls and doing the same for them).
In terms of how precisely I'm doing the transition, I've specified an object that conforms to UIViewControllerAnimatedTransitioning
in the animationControllerForOperation
method:
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController*)fromVC
toViewController:(UIViewController*)toVC
{
if (operation == UINavigationControllerOperationPush)
return [[PushAnimator alloc] init];
return nil;
}
And
@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
I've also done a rendition of the above, setting the frame
of the view rather than the transform
, with the same result.
I've also tried manually make sure that the constraints are re-applied by calling layoutIfNeeded
. I've also tried setNeedsUpdateConstraints
, setNeedsLayout
, etc.
Bottom line, has anyone successfully married custom transition of navigation controller with constraints that use top layout guide?
I solved this by fixing the height constraint of the
topLayoutGuide
. AdjustingedgesForExtendedLayout
wasn't an option for me, as I needed the destination view to underlap the navigation bar, but also to be able to layout subviews usingtopLayoutGuide
.Directly inspecting the constraints in play shows that iOS adds a height constraint to the
topLayoutGuide
with value equal to the height of the navigation bar of the navigation controller. Except, in iOS 7, using a custom animation transition leaves the constraint with a height of 0. They fixed this in iOS 8.This is the solution I came up with to correct the constraint (it's in Swift but the equivalent should work in Obj-C). I've tested that it works on iOS 7 and 8.