前言
笔者在做公司项目(mini)的时候被这个很简单的问题困扰了很久,出现的bug是Label的父控件总是超出了范围,特别是在重新设置字体的时候,这个问题很明显,之前还以为是系统的问题10.3,后面用来自己的手机系统(9.3)也总是会有问题,不能够精确的计算文字的高度导致scrollview的contentSize计算有误!
解决问题
我们都知道在重新布局子控件的时候要调用- (void)layoutSubviews{ [super layoutSubviews];}
关键是怎么调用,笔者出现了一个重大的笔误我想当然的调用[self setNeedsLayout]
然而效果并没有什么用,它虽然能布局子控件,但并不能及时刷新,于是我又通过调用[self LayoutIfNeed]
完美的解决了这个bug!
总价一些layout方法
- layoutSubviews
- layoutIfNeeded
- setNeedsLayout
- setNeedsDisplay
- drawRect
- sizeThatFits
- sizeToFit
- boundingRectWithSize
这些是常用的,肯定还有其他很多欢迎补充
layoutSubviews
这个方法,默认没有做任何事情,需要子类进行重写 。 系统在很多时候会去调用这个方法:
- 初始化不会触发layoutSubviews,但是如果设置了不为 CGRectZero的frame的时候就会触发。
- addSubview会触发layoutSubviews
- 设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化
- 滚动一个UIScrollView会触发layoutSubviews
- 旋转Screen会触发父UIView上的layoutSubviews事件
- 改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件
在苹果的官方文档中强调: You should override this method only if the autoresizing behaviors of the subviews do not offer the behavior you want.layoutSubviews, 当我们在某个类的内部调整子视图位置时,需要调用。反过来的意思就是说:如果你想要在外部设置subviews的位置,就不要重写。
setNeedsLayout
标记为需要重新布局,不立即刷新,(那有什么用)但layoutSubviews一定会被调用
配合layoutIfNeeded立即更新
layoutIfNeeded
如果,有需要刷新的标记,立即调用layoutSubviews进行布局
drawRect
这个方法是用来重绘的(平时用的少,就不过多总结,网上一大把)配合setNeedsDisplay
size to fit
这个方法可以手动计算文字的宽高度
- sizeToFit会自动调用sizeThatFits方法;
- sizeToFit不应该在子类中被重写,应该重写sizeThatFits
- sizeThatFits传入的参数是receiver当前的size,返回一个适合的size
- sizeToFit可以被手动直接调用sizeToFit和sizeThatFits方法都没有递归,对subviews也不负责,只负责自己
boundingRectWithSize
我发现用boundingRectWithSize计算高度的时候会计算失误,就是短一些,但是不知道短多少,后来发现是短了字体高度的一半,加上这个高度才是正确的高度。可能是label必须留出上下的这个高度才可以吧。(摘抄网上的bug,笔者目前暂未发现,平时用的都挺好的)