在iOS上,屏幕上绘制任何内容的整体机制是什么?

Sar*_*h W 2 user-interface cocoa-touch ios

我想知道为什么我们是子类UIView,并且我们实现了一个drawRect被调用的方法,但同时,如果我们向这个视图添加按钮或标签,并调整它们的位置坐标,那么它们也会被重新绘制.因此,对于这个视图似乎有两种绘制机制,一种是为自己绘制,另一种是在该视图中用于对象.

但事实证明,似乎每隔1/60秒,整棵树就被遍历了.从顶部视图对象开始,iOS版将访问所有的孩子们,然后调用drawRectself,和孩子们还参观了同样的方式,将孙子被访问,并且drawRect被每一个信息的第一级的孩子,如:

-(void) processViewObject:(UIView *) obj {
    // pseudo code:
    foreach children "c" already sorted by zOrder from most negative to -1
        processViewObject(c)    // recursion

    if ([self needsUpdateOrNot] == YES)
        [self drawRect]

    foreach children "c" already sorted by zOrder from 1 to the greatest number
        processViewObject(c)   // recursion
}
Run Code Online (Sandbox Code Playgroud)

并且每1/60秒拨打一次电话

processViewObject(topViewObject);    //  start from the topmost view object
Run Code Online (Sandbox Code Playgroud)

因此,任何视图都可以自己绘制drawRect,并且视图的子节点,如果它们的位置坐标被修改,或者它们的内容被更改,那么needsUpdateOrNot之前已经设置了脏位,因此drawRect将调用它们来重新绘制自身.

或者实际上,如果设置了一个视图的脏位,那么这个位可能会传递给递归中的子节点,如:

    foreach children "c" already sorted by zOrder from 1 to the greatest number
        processViewObject(c, [self needsUpdateOrNot])
Run Code Online (Sandbox Code Playgroud)

因此,如果设置了父级的脏位,则还需要重新绘制子项,以便正确绘制此视图中的整个图像.

此外,每个漂亮的按钮或标签只是一个UIView对象,drawRect已经实现了一个可以绘制一个好看的图像 - 按钮,复选框,标签或任何其他小部件.

这是如何在屏幕上绘制所有内容的整体机制?我听说"从不称呼drawRect自己,但让它被称为",但从未完全理解为什么,但如果以上是整体机制,那么看起来就是这就是原因.

我想知道这是否与微软Windows或任何GUI操作系统上的实际几乎相同的机制,并且在某些游戏框架上,我认为无论脏位是否设置,所有内容都被绘制,因为据称,事物在游戏中一直移动,框架只需要每隔1/60秒绘制所有这些内容.

zOrder上面的处理顺序是在某个框架的代码中,因此首先绘制所有负zOrder子项,然后self绘制,然后绘制所有正zOrder子项.(这就是zOrder如何以画家模型的方式在屏幕上绘制东西 - 后者绘制将覆盖之前绘制的东西.)因此self,0如果是相对于孩子的zOrder - zOrder数量的self事项,如果它与自己的兄弟姐妹相关,而不是与孩子相关.

以上是准确的吗?如果给出答案,如果可能的话,可以引用部分源代码或引用,以便我们知道这是它的工作方式的标准或官方方式?

Bra*_*son 6

我认为你把绘画与合成混淆了.这两个是不同的概念,它们在不同的点上发挥作用.

在iOS上,每个UIView都有一个CALayer支持,它实际上是一个围绕矩形OpenGL ES纹理的轻量级包装器.当需要完全重绘UIView时(第一次出现,或者在不同情况下强制重绘时),-drawRect:会触发UIView 并使用Core Graphics将矢量图形渲染成位图.然后,该位图通过CALayer上传到GPU并存储在那里.

当需要移动视图或对其应用简单变换(旋转,缩放等)时,不会重新绘制视图,只需移动背衬层并合成可见场景中的图层.同样,每个视图和子视图都有自己的后备层,因此它们在视图(层)层次结构中以Z顺序合成.在GPU上进行合成是一种非常快速的操作,比最初的视图绘制要快得多.这是在iOS中实现平滑滚动或动画的原因,因为这些底层矩形图像只是在GPU上移动并进行合成.这也是为什么视图和图层中的透明度会降低滚动等操作的原因,因为合成非不透明图层的速度明显慢于不透明图层.

移动子视图或位于其上方的其他视图时,不会重绘视图的重叠部分,因为合成会处理可见和不可见的内容.实际-drawRect:重绘的唯一时间是当您使用-setNeedsDisplay强制重新渲染时,或者如果您needsDisplayOnBoundsChange为CALayer 设置,以便它重新绘制自身以响应大小或形状的变化.

我相信jturton链接到的文档部分在iOS上或Mac上的图层支持视图时是不正确的.它似乎是在Mac缺少Core Animation时编写的,并且是非层支持的NSView呈现的方式,因此它可能是从较旧的引用中复制和粘贴的.对于图层支持的视图不是这种情况,这些视图在部分遮挡时不会重绘.您可以通过-drawRect:在层支持的UIView中调用何时调用来自行测试,并且当视图简单地相互移动时,您将看到它不会被触发.