Autolayout constraints and child view controller
I have a similar situation where I add a child controller to a visible controller (a popup).
I define the child view controller in interface builder. It's viewDidLoad method just calls setTranslatesAutoresizingMaskIntoConstraints:NO
Then I define this method on the child controller which takes a UIViewController parameter, which is the parent. This method adds itself to the given parent view controller and defines its own constraints:
- (void) addPopupToController:(UIViewController *)parent {
UIView *view = [self view];
[self willMoveToParentViewController:parent];
[parent addChildViewController:self];
[parent.view addSubview:view];
[self didMoveToParentViewController:parent];
NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[view]-0-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(view)];
[parent.view addConstraints:horizontalConstraints];
NSArray *verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[view]-0-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(view)];
[parent.view addConstraints:verticalConstraints];
}
then inside the parent UIViewController (the one which is already displayed), when I want to display my child popup view controller it calls:
PopUpNotificationViewController *popup = [[self storyboard] instantiateViewControllerWithIdentifier:@"NotificationPopup"];
[popup addPopupToController:self];
You can define whatever constraints you want on the child controller's view when adding it to the parent controller's view.
You can add constraints right after invoke of addSubview: , don't forget to set translatesAutoresizingMaskIntoConstraints
to false
Here is a code snippet of adding and hiding child view controller with constraints (inspired by apple guide)
Display
private func display(contentController content : UIViewController)
{
self.addChildViewController(content)
content.view.translatesAutoresizingMaskIntoConstraints = false
self.containerView.addSubview(content.view)
content.didMove(toParentViewController: self)
containerView.addConstraints([
NSLayoutConstraint(item: content.view, attribute: .top, relatedBy: .equal, toItem: containerView, attribute: .top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: content.view, attribute: .bottom, relatedBy: .equal, toItem: containerView, attribute: .bottom, multiplier: 1, constant: 0),
NSLayoutConstraint(item: content.view, attribute: .leading, relatedBy: .equal, toItem: containerView, attribute: .leading, multiplier: 1, constant: 0),
NSLayoutConstraint(item: content.view, attribute: .trailing, relatedBy: .equal, toItem: containerView, attribute: .trailing, multiplier: 1, constant: 0)
])
}
Hide
private func hide(contentController content : UIViewController)
{
content.willMove(toParentViewController: nil)
content.view.removeFromSuperview()
content.removeFromParentViewController()
}
I think the
layoutIfNeeded
method will only work if you have previously calledsetNeedsLayout
. If you usesetNeedsLayout
instead, the system will know to update at an appropriate time. Try changing that in your code.When you add constraints to a view, that view should automatically layout its subviews again to account for the new constraints. There should be no need to call
setNeedsLayout
unless something has changed since you have added the constraints. Are you adding the constraints to a view and if so: are you adding them to the right view?One thing you can try is to subclass
UIView
so that you see a log message whenever theChildViewController.view
orParentViewController.view
performs a fresh layout:-(void) layoutSubviews { [super layoutSubviews]; NSLog(@"layoutSubviews was called on the following view: %@", [view description]); }
Maybe that will reveal something about when your views are (or aren't) layout out their subviews.