iOS中UIview layout相关方法

在使用UIview的时候,与之相关几个layout方法总是容易搞混,所以就总结一下
首先列出与layout相关的几个方法

  • layoutSubviews
  • setNeedsLayout
  • layoutIfNeeded
  • setNeedsDisplay
  • drawRect
  • sizeThatFits
  • sizeToFit

下面就来分别说说这几个方法

layoutSubviews

layoutSubviews在以下情况下会被调用:

  1. init初始化不会触发layoutSubviews。
  2. addSubview会触发layoutSubviews。
  3. 设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化。
  4. 滚动一个UIScrollView会触发layoutSubviews。
  5. 旋转Screen会触发父UIView上的layoutSubviews事件。
  6. 改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。
  7. 直接调用setLayoutSubviews。

官方文档对这个方法的说明:

You should override this method only if the autoresizing behaviors of the subviews do not offer the behavior you want.layoutSubviews

意思就是当我们在某个类的内部调整子视图位置时,需要调用这个方法。

setNeedsLayout

标记为需要重新布局,不立即刷新,会默认调用layoutSubviews。

layoutIfNeeded

如果,有需要刷新的标记,立即调用layoutSubviews进行布局

setNeedsDisplay

setNeedsDisplay会自动调用drawRect方法,这样可以拿到 UIGraphicsGetCurrentContext,就可以进行绘制了。

drawRect

drawRect在以下情况下会被调用:

  1. 如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。drawRect调用是在Controller->loadView, Controller->viewDidLoad 两方法之后掉用的.所以不用担心在控制器中,这些View的drawRect就开始画了.这样可以在控制器中设置一些值给View(如果这些View draw的时候需要用到某些变量值).
  2. 该方法在调用sizeToFit后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。
  3. 通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。
  4. 直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0。

drawRect方法使用注意点:

  1. 若使用UIView绘图,只能在drawRect:方法中获取相应的contextRef并绘图。如果在其他方法中获取将获取到一个invalidate的ref并且不能用于画图。drawRect:方法不能手动显示调用,必须通过调用setNeedsDisplay 或者 setNeedsDisplayInRect,让系统自动调该方法。
  2. 若使用CAlayer绘图,只能在drawInContext: 中(类似于drawRect)绘制,或者在delegate中的相应方法绘制。同样也是调用setNeedDisplay等间接调用以上方法
  3. 若要实时画图,不能使用gestureRecognizer,只能使用touchbegan等方法来掉用setNeedsDisplay实时刷新屏幕

sizeThatFits And sizeToFit

sizeThatFits的官方说明:

The default implementation of this method returns the existing size of the view. Subclasses can override this method to return a custom value based on the desired layout of any subviews. For example, a UISwitch object returns a fixed size value that represents the standard size of a switch view, and a UIImageView object returns the size of the image it is currently displaying.
This method does not resize the receiver.

这个方法默认会返回view当前的尺寸,子类可以重写这个方法根据子视图的期望返回自定义的值。

sizeToFit的官方说明:

Call this method when you want to resize the current view so that it uses the most appropriate amount of space. Specific UIKit views resize themselves according to their own internal needs. In some cases, if a view does not have a superview, it may size itself to the screen bounds. Thus, if you want a given view to size itself to its parent view, you should add it to the parent view before calling this method.
You should not override this method. If you want to change the default sizing information for your view, override the sizeThatFits: instead. That method performs any needed calculations and returns them to this method, which then makes the change.

当你想调整当前view的尺寸的时候调用这个方法,view根据内部需要调整自己的尺寸。如果一个view没有父视图,它可能调整自己适应屏幕。如果你想调整一个有父视图的view的尺寸,你应该在当前view添加到父视图之前调用这个方法。
如果你想改变一个view的默认尺寸,你应该重写sizeThatFits。sizeThatFits会进行计算并把新的尺寸返回给你。

调用sizeToFit的时候,类似于系统会根据内容的帮我布局一个它认为最合适的大小。
我们一般在不方便手动布局的时候才调用sizeToFit方法

  1. navigationBar中对navigationItem的设置,(添加两个视图以上的控件到Item)

  2. toolBar中的对UIBarButtonItem的设置(一般还要添加弹簧控件)

  3. 在tabBar中我们不能手动的添加的子控件,因为tabBar是根据控制器系统默认自动添加的tabBarItem。(系统可能也会自动调用了这个方法)

  4. UILabel中添加文字,然后让调整label的大小来适应文字,我们也调用sizeToFit的方法。