Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autolayout height changes when I push a new view controller

Edit: I fixed my problem, but I would be interested in understanding why my fix works. See below.

I use autolayout to build my UITableViewCells.

The cell is pretty simple with 2 labels (purple and yellow) and a textfield (green).

my cell

This works fine when displaying the first time. But when I push a new view controller, the view instantly rearranges itself. The purple label gets bigger for whatever reason.

Here is an example where I click the "Parent Account ID" cell to push a new view controller. Notice that as soon as the transition begins, the layout changes. When I come back it is still changed.

cell animation gif

The items are created with [UILabel new] with no frame.

[self.contentView addSubview:self.textLabel];
[self.contentView addSubview:self.errorLabel];
[self.contentView addSubview:self.textField];

Then the autolayout is created using Masonry.

UIEdgeInsets insets = UIEdgeInsetsMake(3, 15, 3, 15);

[self.textLabel makeConstraints:^(MASConstraintMaker *make) {
    make.left.top.equalTo(self.contentView).insets(insets);
    make.width.priorityLow();
}];

[self.errorLabel makeConstraints:^(MASConstraintMaker *make) {
    make.top.right.equalTo(self.contentView).insets(insets);
    make.left.equalTo(self.textLabel.right).offset(5);
}];

[self.textField makeConstraints:^(MASConstraintMaker *make) {
    make.left.bottom.right.equalTo(self.contentView).insets(insets);
    make.top.equalTo(self.textLabel.bottom).insets(insets);
}];

Notice that I never specify a height because I don't really care about the height. (as long as it is consistent!)

Any idea why this could change? Thanks

Edit: I found a fix.

I now also set the autolayout properties of contentView.

[self.contentView makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(self);
}];

I am still interested in understanding why the contentView changes its size!

like image 511
Jonas Schmid Avatar asked Aug 08 '14 10:08

Jonas Schmid


1 Answers

Your fix works because it enforces a missing constraint.

First, let's start by writing down the constraints that you created using Masonry:

  1. The purple view must be aligned left.
  2. The purple view must be aligned top.
  3. The purple view's width can vary but it's min and max aren't that important.
  4. The yellow view must be aligned right.
  5. The yellow view must be aligned top.
  6. The yellow view's left edge must be 5px away from the purple view's right edge.
  7. The green view must be aligned left.
  8. The green view must be aligned bottom.
  9. The green view must be aligned right.
  10. The green view's top edge must be 0px away from the purple view's bottom edge.

This might seem complete but it allows autolayout to draw your views in many different ways.

Consider the following:


According to the rules you have created above, all three possibilities are true. As you tap on a cell, the layout is invalidated and redrawn. Given that your cell can be drawn a few different ways, it will simply draw itself and satisfy all of your constraints... and it does.

I'll be honest, I'm not 100% sure what make.edges.equalTo(self); does exactly since it is a bit ambiguous. However, one thing is for sure is that it adds the missing constraints you were looking for.

Possible missing constraints are:

  1. The purple view's height must be equal to the green view's height.
  2. The yellow view's height must be equal to the purple view's height.
  3. The green view's height must be equal to the yellow view's height.

Hope this clarifies it for you.

like image 176
bsarrazin Avatar answered Nov 09 '22 04:11

bsarrazin