In the code below, these four methods are called for layout reasoning. I'm a little confused why all of them are needed, though, and what they do differently from one another. They're used in the process to make a cell's height be dynamic with Auto Layout. (Taken from this repository from this question.)
[cell setNeedsUpdateConstraints]; [cell updateConstraintsIfNeeded]; [cell.contentView setNeedsLayout]; [cell.contentView layoutIfNeeded];
And it's from this block of code for the cell's height:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { RJTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; [cell updateFonts]; NSDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:indexPath.row]; cell.titleLabel.text = [dataSourceItem valueForKey:@"title"]; cell.bodyLabel.text = [dataSourceItem valueForKey:@"body"]; cell.bodyLabel.preferredMaxLayoutWidth = tableView.bounds.size.width - (kLabelHorizontalInsets * 2.0f); [cell setNeedsUpdateConstraints]; [cell updateConstraintsIfNeeded]; [cell.contentView setNeedsLayout]; [cell.contentView layoutIfNeeded]; CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; return height; }
But what are they doing differently? Why are they all needed?
Suppose you encapsulate your view logic in a UIView
subclass, and call it SomeView
. This means that SomeView
should know how to layout itself, that is, how to position some other views inside it (you can also create a view that draws itself without using any subviews, but that's beyond the needs of an average developer).
This layout is done by [SomeView layoutSubviews]
. You have an option of overriding it:
subview.frame = CGRectMake(100 + shiftX, 50 + shiftY, 250 + shiftX - paddingRight, ... // Oh no, I think I didn't do it right.
but you rarely need to do so. In the dark ages of Cocoa Touch, this manual layout was widespread, but now I'd say 99% of layouts can be covered with Auto Layout.
The system needs to know when it should call [UIView layoutSubviews]
. It's obviously done the first time you need to draw a view, but it may be also called whenever the superview frame changes. Here's a detailed explanation.
So the system often calls [view layoutIfNeeded]
. You can also call it at any time, but this will have an effect only if there is some event that has called [view setNeedsLayout]
or if you have called it manually, as in this case.
The Auto Layout (capitalized this way in the documentation) is called like that because you're leaving [SomeView layoutSubviews]
as it is inherited from UIView
and describe the position of your subviews instead in terms of constraints.
When using Auto Layout, system will perform calls to [view updateConstraintsIfNeeded]
at each layout pass. However, only if the flag [view setNeedsUpdateConstraints];
is set, the method calls into -updateConstraints
(which does the real job).
If you don't use Auto Layout, those methods are not relevant.
You can implement it like in this example.
It's rarely necessary to call -layoutIfNeeded
and -updateConstraintsIfNeeded
directly, because UI engine will do that automatically at each layout pass. However, in this case the author has chosen to call them immediately; this is because the resulting height is needed right now, not at some point in the future.
This method of updating the cell's height seems right. Note that cell
could be a newly created cell and thus not added into view hierarchy yet; this does not impact its ability to layout itself.
In your custom view go with the following options, starting from the most 'universal' to most 'customized':
-updateConstraints
. -layoutSubviews
.In the code that changes something that could make your view's constraints change, call
[view setNeedsUpdateConstraints];
If you need results immediately, call also
[view updateConstraintsIfNeeded];
If the code changes view's frame use
[view setNeedsLayout];
and finally if you want the results immediately, call
[view layoutIfNeeded];
This is why all four calls are required in this case.
Take a look at detailed explanation in the article Advanced Auto Layout Toolbox, objc.io issue #3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With