Search code examples
iosobjective-cuiviewautolayoutnslayoutconstraint

Auto-layout constraints not getting respected


I am programmatically creating constraints such that the view controller view has a background view and a toolbar, with the toolbar at the bottom. I want the background view's height to decrease as the height of the toolbar increases. After adding the background view and the toolbar as subviews to the view controller's view, I call (in viewDidLoad) the following method that programmatically sets the constraints.

- (void)configureConstraintsForBackgroundViewAndToolbar {

    [self.backgroundView setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.toolbarComponent setTranslatesAutoresizingMaskIntoConstraints:NO];

    UIView *constraintsBackgroundView = self.backgroundView;
    UIView *constraintsToolbar = self.toolbarComponent;

    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(
                                    constraintsBackgroundView, 
                                    constraintsToolbar);
    NSDictionary *metricsDictionary = @{
                                        @"toolbarHeight":[NSNumber numberWithFloat:TOOLBAR_HEIGHT]
                                        };

    [NSLayoutConstraint activateConstraints:
            [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(0)-[constraintsBackgroundView]-(0)-|" 
            options:NSLayoutFormatDirectionLeadingToTrailing 
            metrics:metricsDictionary 
            views:viewsDictionary]];

    [NSLayoutConstraint activateConstraints:
            [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(0)-[constraintsToolbar]-(0)-|" 
            options:NSLayoutFormatDirectionLeadingToTrailing 
            metrics:metricsDictionary 
            views:viewsDictionary]];

    [NSLayoutConstraint activateConstraints:
            [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(0)-[constraintsBackgroundView]-(0)-[constraintsToolbar(>=toolbarHeight)]-(0)-|" 
            options:NSLayoutFormatDirectionLeadingToTrailing 
            metrics:metricsDictionary 
            views:viewsDictionary]];
}

This works fine till the moment I try to update the height of the toolbar using the following method (via an embedded text view). Is there something wrong that I am doing here? The toolbar height increases but the background view does not shorten in height (I debug that using the SparkInspector). Seems pretty straightforward that am missing something obvious here...

- (void)textViewDidChange:(UITextView *)textView {

    if (textView != self.toolbarTextView) {
        return;
    }

    CGFloat currentHeight = self.bounds.size.height;

    CGSize size = [textView sizeThatFits:CGSizeMake(textView.frame.size.width, textView.frame.size.height)];
    CGFloat determinedHeight = fminf(fmaxf(size.height, TOOLBAR_HEIGHT), MAX_TOOLBAR_HEIGHT);

    [self setBounds:CGRectMake(0, 0, self.bounds.size.width, determinedHeight)];    

    [self setNeedsLayout];
}

Also, if I query the toolbar and the background view for their constraints, the constraints between each other that I have set up initially do not come up? They do show only for the view controller's view... that doesn't sound right to me either...?

Many thanks...


Solution

  • If you are setting up your layout with constraints it does not make sense to set bounds or frame for your views to update the layout. Instead add constraints in a way that you can edit your layout by changing the constant property of the constraint

    For example:

    Set height for your toolbar using a specific constraint and store it in a property

    NSLayoutConstraint *toolBarHeightConstraint = [NSLayoutConstraint constraintWithItem:constraintsToolbar
                                                                               attribute:NSLayoutAttributeHeight
                                                                               relatedBy:NSLayoutRelationEqual
                                                                                  toItem:self.view
                                                                               attribute:NSLayoutAttributeNotAnAttribute
                                                                              multiplier:1
                                                                                constant:TOOLBAR_HEIGHT];
    

    Then change the height of the toolbar by changing the constant for the constraint. like:

    toolBarHeightConstraint.constant = newHeight;
    

    In your case you will also need to change your vertical constraint to:

    [NSLayoutConstraint activateConstraints:
                [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(0)-[constraintsBackgroundView]-(0)-[constraintsToolbar]-(0)-|" 
                options:NSLayoutFormatDirectionLeadingToTrailing 
                metrics:metricsDictionary 
                views:viewsDictionary]];
    

    For more information have a look at this answer.