Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to size and position an embedded UIViewController using Auto Layout constraints?

Here is what I wanna do: My storyboard contains a UIViewController with just a few controlls. It's height is less than half a screen. For simplicity, let's call it the DataViewController. The DataViewController is embedded inside other UIViewControllers through a "Container View".

Although "Container View" displays the DataViewController, it still needs to have an explicit height set. Otherwise interface builder complains about ambiguous constraints.

Now, how can I tell "Container View" that it's size should be what's required by DataViewController? I.e. without setting a hard coded, explicit height in Interface Builder (which, I fear, would break the layout if the font size changes)?

Or in other words: How do you size/position embedded UIViewControllers in Interface Builder?

like image 363
SePröbläm Avatar asked Mar 18 '16 14:03

SePröbläm


1 Answers

If you want the childViewContainer to be responsible for its width and height, here is a way to do it :

  • Set width and height constraints in your Parent View Controller(s) and select remove at build time. They are just here so interface builder stops complaining about missing constraints. enter image description here

  • (You can) Change your Child View Controller simulated size from fixed to freeform in your storyboard size inspector tab.

enter image description here

  • Here is the trick : In your Parent View Controller(s) viewDidLoad disable translatesAutoresizingMaskIntoConstraints on the first subviews, and simply redefine by yourself the containerView constraints to its subview - root view of your Child View Controller - like bellow :

Objective-C

- (void)viewDidLoad {
    [super viewDidLoad];
    self.containerView.subviews[0].translatesAutoresizingMaskIntoConstraints = NO;
}

#pragma mark - Constraints

- (void)updateViewConstraints {
    [super updateViewConstraints];
    [self initConstraints];
}

- (void)initConstraints {
    if (!self.didSetConstraints) {
        self.didSetConstraints = YES;

        self.containerView.subviews[0].translatesAutoresizingMaskIntoConstraints = NO;

        NSDictionary *views = @{@"subview" : self.containerView.subviews[0]};

        [self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[subview]|" options:0 metrics:nil views:views]];
        [self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[subview]|" options:0 metrics:nil views:views]];
    }
}

Swift

override func viewDidLoad() {
    super.viewDidLoad()
    containerView.subviews[0].translatesAutoresizingMaskIntoConstraints = false
}

// Mark: Constraints

override func updateViewConstraints() {
    super.updateViewConstraints()
    initConstraints()
}

func initConstraints() {
    if !didSetConstraints {
        didSetConstraints = true

        containerView.subviews[0].translatesAutoresizingMaskIntoConstraints = false

        let views = ["subview": containerView.subviews[0]]

        containerView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[subview]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
        containerView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[subview]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
    }
}

Now your child View Controller (linked to the container view) is fully responsible for its content size. Thus, you must set constraints that let the root view calculates its size to satisfies the constraints it holds.

like image 108
Tanguy G. Avatar answered Sep 27 '22 22:09

Tanguy G.