You always have to call [super layoutSubviews] last, if the intrinsic content size of a view will be changed. If you change the title of the button, the intrinsic content size of the UIButton will be changed, therefore the last call.
viewWillLayoutSubviews()Called to notify the view controller that its view is about to layout its subviews.
I had a similar question, but wasn't satisfied with the answer (or any I could find on the net), so I tried it in practice and here is what I got:
init
does not cause layoutSubviews
to
be called (duh)addSubview:
causes
layoutSubviews
to be called on the
view being added, the view it’s being
added to (target view), and all the
subviews of the targetsetFrame
intelligently calls layoutSubviews
on
the view having its frame set only
if the size parameter of the frame is
differentlayoutSubviews
to be called on
the scrollView, and its superviewlayoutSubview
on the parent view (the
responding viewControllers primary
view)layoutSubviews
on its superview (Important: views with an intrinsic content size will re-size if the content that determines their size changes; for example, updating the text on a UILabel will cause the intrinsic content size to be updated and thus call layoutSubviews
on its superview)My results - http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-called/
Building on the previous answer by @BadPirate, I experimented a bit further and came up with some clarifications/corrections. I found that layoutSubviews:
will be called on a view if and only if:
Some relevant details:
layoutSubviews:
is called whenever a UIScrollView scrolls, as it performs the scrolling by changing its bounds' origin.layoutSubviews:
when the view is eventually added to a view hierarchy.setNeedsLayout
, which sets/raises a flag. Each iteration of the run loop, for all views in the view hierarchy, this flag is checked. For each view where the flag is found raised, layoutSubviews:
is called on it and the flag is reset. Views higher up the hierarchy will be checked/called first.https://developer.apple.com/library/prerelease/tvos/documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/CreatingViews/CreatingViews.html#//apple_ref/doc/uid/TP40009503-CH5-SW1
Layout changes can occur whenever any of the following events happens in a view:
a. The size of a view’s bounds rectangle changes.
b. An interface orientation change occurs, which usually triggers a change in the root view’s bounds rectangle.
c. The set of Core Animation sublayers associated with the view’s layer changes and requires layout.
d. Your application forces layout to occur by calling thesetNeedsLayout
orlayoutIfNeeded
method of a view.
e. Your application forces layout by calling thesetNeedsLayout
method of the view’s underlying layer object.
Some of the points in BadPirate's answer are only partially true:
For addSubView
point
addSubview
causes layoutSubviews to be called on the view being added, the view it’s being added to (target view), and all the subviews of the target.
It depends on the view's (target view) autoresize mask. If it has autoresize mask ON, layoutSubview will be called on each addSubview
. If it has no autoresize mask then layoutSubview will be called only when the view's (target View) frame size changes.
Example: if you created UIView programmatically (it has no autoresize mask by default), LayoutSubview will be called only when UIView frame changes not on every addSubview
.
It is through this technique that the performance of the application also increases.
For the device rotation point
Rotating a device only calls layoutSubview on the parent view (the responding viewController's primary view)
This can be true only when your VC is in the VC hierarchy (root at window.rootViewController
), well this is most common case. In iOS 5, if you create a VC, but it is not added into any another VC, then this VC would not get any noticed when device rotate. Therefore its view would not get noticed by calling layoutSubviews.
I tracked the solution down to Interface Builder's insistence that springs cannot be changed on a view that has the simulated screen elements turned on (status bar, etc.). Since the springs were off for the main view, that view could not change size and hence was scrolled down in its entirety when the in-call bar appeared.
Turning the simulated features off, then resizing the view and setting the springs correctly caused the animation to occur and my method to be called.
An extra problem in debugging this is that the simulator quits the app when the in-call status is toggled via the menu. Quit app = no debugger.
calling
[self.view setNeedsLayout];
in viewController makes it to call viewDidLayoutSubviews
have you looked at layoutIfNeeded?
The documentation snippet is below. Does the animation work if you call this method explicitly during the animation?
layoutIfNeeded Lays out the subviews if needed.
- (void)layoutIfNeeded
Discussion Use this method to force the layout of subviews before drawing.
Availability Available in iPhone OS 2.0 and later.
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