美文网首页
iOS layoutSubviews

iOS layoutSubviews

作者: 言霏 | 来源:发表于2020-04-02 16:05 被阅读0次

    触发时机(参考):

      1. 自身被init(frame: CGRect)创建出来且CGRect不会zero时。
      1. addSubview的时候。
      1. 当自身或子视图size发生改变的时候。
      1. 滑动UIScrollView的时候。
      1. 旋转Screen会触发父UIView上的layoutSubviews事件。

    着重讨论下比较复杂的第二条情况(子视图size发生改变的时候)。
    建立如下白板Demo

    image.png
    ViewController中添加橙色父视图,其中含有Change按钮、紫色子视图,且给紫色视图添加autolayout。
    image.png

    完整代码:

    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            
        }
    }
    
    class OrangeView: UIView {
        
        @IBOutlet weak var purpleView: UIView!
        @IBOutlet weak var purpleViewH: NSLayoutConstraint!
        
        override func layoutSubviews() {
            super.layoutSubviews()
            
            print(#function)
        }
        
        @IBAction func clickBtn(_ sender: Any) {
            
            changeConstraint()
        }
        
        func changeConstraint() {
            if purpleViewH.constant == 30.0 {
                purpleViewH.constant = 160.0
            } else {
                purpleViewH.constant = 30.0
            }
            
            print(purpleView.frame.size.height)
        }
    }
    

    此时点击Change按钮,紫色视图变为160高度,打印:

    image.png
    可以看到即使更改了purpleViewH.constant = 160.0但是purpleView.frame.size.height仍为30.0,这种情况是在purpleViewH.constant = 160.0时橙色视图被标记为“需要刷新”,在当前runloop结束时才会调用layoutSubviews方法进行真正刷新,故打印仍为30.0
    更改changeConstraint ()为:
    func changeConstraint() {
            if purpleViewH.constant == 30.0 {
                purpleViewH.constant = 160.0
            } else {
                purpleViewH.constant = 30.0
            }
            
            self.layoutIfNeeded()
            print(purpleView.frame.size.height)
        }
    

    紫色视图变为160高度。打印:

    image.png
    purpleViewH.constant = 160.0将橙色视图被标记为“需要刷新”,layoutIfNeeded()会把“需要刷新”的视图立即去调用layoutSubviews()purpleView.frame.size.height也被更新为160.0
    更改changeConstraint ()为:
    func changeConstraint() {
        self.layoutIfNeeded()
        print(purpleView.frame.size.height)
    }
    

    打印:

    image.png
    此时layoutSubviews()不会被调用,紫色视图依旧也给30.0高度。
    更改changeConstraint ()为:
    func changeConstraint() {
            self.setNeedsLayout()
            self.layoutIfNeeded()
            print(purpleView.frame.size.height)
        }
    

    打印:

    image.png
    setNeedsLayout()的作用就是标记当前视图为“需要刷新”(即使其实没必要刷新的),layoutIfNeeded ()才会立即去调用了layoutSubviews()

    将紫色视图的autoLayout删掉,同时更改代码为:

    @IBAction func clickBtn(_ sender: Any) {
            
            changeFrame()
        }
        
        func changeFrame() {
            if purpleView.bounds.height == 30.0 {
                purpleView.bounds = CGRect.init(x: 0, y: 0, width: purpleView.bounds.width, height: 160.0)
            } else {
                purpleView.bounds = CGRect.init(x: 0, y: 0, width: purpleView.bounds.width, height: 30.0)
            }
            
            print(purpleView.frame.size.height)
        }
    
    

    紫色视图变为高度160.0,打印:

    image.png
    用bounds、frame进行布局,会立即改变,在当前runloop结束时调用layoutSubviews ()
    更改changeFrame ()为:
        func changeFrame() {
            if purpleView.bounds.height == 30.0 {
                purpleView.bounds = CGRect.init(x: 0, y: 0, width: purpleView.bounds.width, height: 160.0)
            } else {
                purpleView.bounds = CGRect.init(x: 0, y: 0, width: purpleView.bounds.width, height: 30.0)
            }
            self.layoutIfNeeded()
            print(purpleView.frame.size.height)
        }
    
    

    紫色视图变为高度160.0,打印:

    image.png
    如果自身已经被标记了“需要刷新”(可能是由于改变autolayout、bounds等的值被系统自动标记,也可能是setNeedsLayout强制标记)layoutIfNeeded ()就会立即调用layoutSubviews()
    更改changeFrame ()为:
        func changeFrame() {
            self.setNeedsLayout()
            print(purpleView.frame.size.height)
        }
    
    

    打印:

    image.png
    setNeedsLayout()将当前视图强制标记为“需要刷新”,在runloop当前周期结束前调用layoutSubviews()

    可以得出结论setNeedsLayout()是将当前视图强制标记为“需要刷新”,在runloop当前周期结束前调用layoutSubviews()
    如果视图已经被标记了“需要刷新”,layoutIfNeeded()就会立即调用layoutSubviews(),同时将视图标记为“不需要刷新”,以免在runloop当前周期结束前又调用次layoutSubviews()
    能将视图标记为“需要刷新”的方式就是开头说的那几种。

    相关文章

      网友评论

          本文标题:iOS layoutSubviews

          本文链接:https://www.haomeiwen.com/subject/josxphtx.html