[ios] When is layoutSubviews called?

I have a custom view that's not getting layoutSubview messages during animation.

I have a view that fills the screen. It has a custom subview at the bottom of the screen that correctly resizes in Interface Builder if I change the height of the nav bar. layoutSubviews is called when the view is created, but never again. My subviews are correctly laid out. If I toggle the in-call status bar off, the subview's layoutSubviews is not called at all, even though the main view does animate its resize.

Under what circumstances is layoutSubviews actually called?

I have autoresizesSubviews set to NO for my custom view. And in Interface Builder I have the top and bottom struts and the vertical arrow set.


Another part of the puzzle is that the window must be made key:

[window makeKeyAndVisible];

of else the subviews are not automatically resized.

This question is related to ios cocoa-touch autolayout bounds layoutsubviews

The answer is


Some of the points in BadPirate's answer are only partially true:

  1. 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.

  2. 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.


When migrating an OpenGL app from SDK 3 to 4, layoutSubviews was not called anymore. After a lot of trial and error I finally opened MainWindow.xib, selected the Window object, in the inspector chose Window Attributes tab (leftmost) and checked "Visible at launch". It seems that in SDK 3 it still used to cause a layoutSubViews call, but not in 4.

6 hours of frustration put to an end.


A rather obscure, yet potentially important case when layoutSubviews never gets called is:

import UIKit

class View: UIView {

    override class var layerClass: AnyClass { return Layer.self }

    class Layer: CALayer {
        override func layoutSublayers() {
            // if we don't call super.layoutSublayers()...
            print(type(of: self), #function)
        }
    }

    override func layoutSubviews() {
        // ... this method never gets called by the OS!
        print(type(of: self), #function)
    }
}

let view = View(frame: CGRect(x: 0, y: 0, width: 100, height: 100))

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 target
  • view setFrame intelligently calls layoutSubviews on the view having its frame set only if the size parameter of the frame is different
  • scrolling a UIScrollView causes layoutSubviews to be called on the scrollView, and its superview
  • rotating a device only calls layoutSubview on the parent view (the responding viewControllers primary view)
  • Resizing a view will 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:

  • Its own bounds (not frame) changed.
  • The bounds of one of its direct subviews changed.
  • A subview is added to the view or removed from the view.

Some relevant details:

  • The bounds are considered changed only if the new value is different, including a different origin. Note specifically that is why layoutSubviews: is called whenever a UIScrollView scrolls, as it performs the scrolling by changing its bounds' origin.
  • Changing the frame will only change the bounds if the size has changed, as this is the only thing propagated to the bounds property.
  • A change in bounds of a view that is not yet in a view hierarchy will result in a call to layoutSubviews: when the view is eventually added to a view hierarchy.
  • And just for completeness: these triggers do not directly call layoutSubviews, but rather call 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.

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.


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 the setNeedsLayout or layoutIfNeeded method of a view.
e. Your application forces layout by calling the setNeedsLayout method of the view’s underlying layer object.


calling [self.view setNeedsLayout]; in viewController makes it to call viewDidLayoutSubviews


Examples related to ios

Adding a UISegmentedControl to UITableView Crop image to specified size and picture location Undefined Symbols error when integrating Apptentive iOS SDK via Cocoapods Keep placeholder text in UITextField on input in IOS Accessing AppDelegate from framework? Autoresize View When SubViews are Added Warp \ bend effect on a UIView? Speech input for visually impaired users without the need to tap the screen make UITableViewCell selectable only while editing Xcode 12, building for iOS Simulator, but linking in object file built for iOS, for architecture arm64

Examples related to cocoa-touch

Include of non-modular header inside framework module Move textfield when keyboard appears swift Create space at the beginning of a UITextField Navigation bar with UIImage for title Generate a UUID on iOS from Swift How do I write a custom init for a UIView subclass in Swift? creating custom tableview cells in swift How would I create a UIAlertView in Swift? Get current NSDate in timestamp format How do you add an in-app purchase to an iOS application?

Examples related to autolayout

Autoresize View When SubViews are Added How to update the constant height constraint of a UIView programmatically? Getting a "This application is modifying the autolayout engine from a background thread" error? Programmatically Add CenterX/CenterY Constraints How to trap on UIViewAlertForUnsatisfiableConstraints? How to add constraints programmatically using Swift UICollectionView Self Sizing Cells with Auto Layout Automatic Preferred Max Layout Width is not available on iOS versions prior to 8.0 Remove all constraints affecting a UIView How do I programmatically set device orientation in iOS 7?

Examples related to bounds

Error : Index was outside the bounds of the array. UIView frame, bounds and center UIView's frame, bounds, center, origin, when to use what? When is layoutSubviews called?

Examples related to layoutsubviews

When is layoutSubviews called?