intrinsticContentSize
是自定义UIView子类的固有大小,只要是重写了这个属性的UIView子类(如UILabel,UIButton,UIImageView等),在添加约束时可以只添加位置(position)约束而不添加尺寸(size)约束。但是,这个属性并不完全等于尺寸约束。如果这个属性是动态的,在它改变时,view不会重新layout,即使调用setNeedsLayout()
或者layoutSubviews()
方法也无法再次触发这个方法。官方的解释有说明这一点:
Custom views typically have content that they display of which the layout system is unaware. Setting this property allows a custom view to communicate to the layout system what size it would like to be based on its content. This intrinsic size must be independent of the content frame, because there’s no way to dynamically communicate a changed width to the layout system based on a changed height, for example.
这时我们需要用到invalidateIntrinsticContentSize()
方法来停止使用之前的intrinsticContentSize,并根据新的(当前的)intrinsticContentSize来进行尺寸约束。官方也有明确说明:
Call this when something changes in your custom view that invalidates its intrinsic content size. This allows the constraint-based layout system to take the new intrinsic content size into account in its next layout pass.
不得不说的是,invalidateIntrinsticContentSize()
这个方法的命名误导性极强,只提及了前半部分功能,而完全没有提到后半部分关于重新约束的功能,在没有阅读文档之前,我还一直在使用setNeedsLayout()
和layoutSubviews()
方法试图重新布局,然而,尺寸约束根本没有改变,无论怎么调用这两个方法也不会有任何事情发生,这是让人十分沮丧的事。
另外,由于intrinsticContentSize是在UIViewController的viewDidLoad()
或者LoadView()
方法后执行的,对于那些只在这两个方法中初始化并填充自定义view的流程,上面的讨论是没有意义的。这个讨论是针对那些先初始化,再填充的流程的。