When is layoutSubviews called?

后端 未结 9 1649
忘掉有多难
忘掉有多难 2020-11-22 14:58

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 bo

相关标签:
9条回答
  • 2020-11-22 15:01

    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))
    
    0 讨论(0)
  • 2020-11-22 15:04

    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.

    0 讨论(0)
  • 2020-11-22 15:11

    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.
    0 讨论(0)
  • 2020-11-22 15:13

    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.

    0 讨论(0)
  • 2020-11-22 15:14

    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.

    0 讨论(0)
  • 2020-11-22 15:18

    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.

    0 讨论(0)
提交回复
热议问题