iOS绘制视图流程

2020-09-20  本文已影响0人  song91425

目的:了解View的绘制过程,可以帮我们自定义自己的控件,解决UI界面一下问题,如刷新时机,界面卡顿等一些优化问题。

问题1:什么条件下会调用layoutSubView?

常见情况如下:

需要注意的是:

       layoutSubView这个方法就是一个开关,起到了一个通知的作用,它的功能是告诉系统需要需要重新布局,如果现在这个方法发送通知之前完成某个功能,需要重写它即可。

       在UIView的 layoutSubViews 或者 UIViewController 的 viewDidLayoutSubviews 方法里后可以拿到view的实际frame,所以只有当上面两个方法执行完成frame才会计算出来。所以为什么在viewDidLoad 里通过setFrame的方式,修改原先在storyboard里拖动的约束控件无效。因为updateViewConstraints在viewDidLoad后执行,会覆盖掉之前的设置的frame,所以设置无效。

UI布局刷新

由上面两个方法可知:如果要立即刷新,要先调用[view setNeedsLayout],把标记设为需要布局,然后马上调用[view layoutIfNeeded],如下所示。

[self.view setNeedsLayout];
[self.view layoutIfNeeded];

重绘视图

注意:

 若要实时画图,不能使用gestureRecognizer,只能使用touchbegan等方法来掉用setNeedsDisplay实时刷新屏幕。

在UIView中,呈现给我们的是layer,每一个在 UIKit 中的 view 都有它自己的 CALayer。每一个layer都有一个content,这个content指向的是一块缓存,叫做backing store(后备存储),backing store有点像一个图像。这个后备存储正是被渲染到显示器上的,渲染后的结果就是我们在屏幕上看到是结果。所以绘制流程大概是分为3步:

问题2:只在drawRect方法里才能获取当前图层的上下文?

- (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context {

// 把视图图层对应上下文压入栈顶

UIGraphicsPushContext(context);    

CGRect bounds;    bounds = CGContextGetClipBoundingBox(context);

// 执行drawRect:bounds 方法
[self drawRect:bounds];

// 把上下文出栈
UIGraphicsPopContext();

}

       答:有源码可知iOS系统会维护一个CGContextRef的栈,而UIGraphicsGetCurrentContext()会取栈顶的CGContextRef,当前视图图层的上下文的入栈和出栈操作恰好将drawRect的执行包裹在其中,所以说只在drawRect方法里才能获取当前图层的上下文。

总结:

    iOS完成页面布局总是经历三个过程:测量阶段(updating constraints )--> 布局阶段(layout)--> 显示阶段(display)。

       在updating constraints阶段,在这个阶段主要是计算控件,和控件间的约束,为下一步layout做准备。在这个阶段测量是从下而上,即先测量子view然后再测量父view,重复执行这个过程直到根节点。

       在layout阶段,在这个阶段主要利用是updating constraints阶段的信息设置view的center和bounds,这个layout是从上向下,即先设置父view的center和bounds,再设置子view的,递归的重复这两个步骤,直到全部的view。

       在display阶段,通过上面阶段,手机屏幕还看不到view,只有经过display阶段,iOS系统才会把view渲染到手机屏幕上。这个阶段也是从上而下的,并且这个阶段会调用drawRect方法。

参考:https://www.jianshu.com/p/c49833c04362

上一篇 下一篇

猜你喜欢

热点阅读