Can anyone give a definitive explanation on the relationship between UIView's
setNeedsLayout
, layoutIfNeeded
and layoutSubviews
methods? And an example implementation where all three would be used. Thanks.
What gets me confused is that if I send my custom view a setNeedsLayout
message the very next thing it invokes after this method is layoutSubviews
, skipping right over layoutIfNeeded
. From the docs I would expect the flow to be setNeedsLayout
> causes layoutIfNeeded
to be called > causes layoutSubviews
to be called.
I would like to add on n8gray's answer that in some cases you will need to call
setNeedsLayout
followed bylayoutIfNeeded
.Let's say for example that you wrote a custom view extending UIView, in which the positioning of subviews is complex and cannot be done with autoresizingMask or iOS6 AutoLayout. The custom positioning can be done by overriding
layoutSubviews
.As an example, let's say that you have a custom view that has a
contentView
property and anedgeInsets
property that allows to set the margins around the contentView.layoutSubviews
would look like this:If you want to be able to animate the frame change whenever you change the
edgeInsets
property, you need to override theedgeInsets
setter as follows and callsetNeedsLayout
followed bylayoutIfNeeded
:That way, if you do the following, if you change the edgeInsets property inside an animation block, the frame change of the contentView will be animated.
If you do not add the call to layoutIfNeeded in the setEdgeInsets method, the animation won't work because the layoutSubviews will get called at the next update cycle, which equates to calling it outside of the animation block.
If you only call layoutIfNeeded in the setEdgeInsets method, nothing will happen as the setNeedsLayout flag is not set.
I'm still trying to figure this out myself, so take this with some skepticism and forgive me if it contains errors.
setNeedsLayout
is an easy one: it just sets a flag somewhere in the UIView that marks it as needing layout. That will forcelayoutSubviews
to be called on the view before the next redraw happens. Note that in many cases you don't need to call this explicitly, because of theautoresizesSubviews
property. If that's set (which it is by default) then any change to a view's frame will cause the view to lay out its subviews.layoutSubviews
is the method in which you do all the interesting stuff. It's the equivalent ofdrawRect
for layout, if you will. A trivial example might be:AFAIK
layoutIfNeeded
isn't generally meant to be overridden in your subclass. It's a method that you're meant to call when you want a view to be laid out right now. Apple's implementation might look something like this:You would call
layoutIfNeeded
on a view to force it (and its superviews as necessary) to be laid out immediately.