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

在iOS上,在屏幕上绘制任何内容的总体机制是什么?,ios,cocoa-touch,user-interface,Ios,Cocoa Touch,User Interface,起初我想知道为什么如果我们将UIView子类化,并实现要调用的drawRect方法,但同时,如果我们向该视图添加按钮或标签,并调整它们的位置坐标,它们也将被重新绘制。。。因此,这个视图似乎有两种绘图机制,一种用于自身,另一种用于视图中的对象 但事实证明,似乎每1/60秒,整个树就被遍历一次。从俯视图对象开始,iOS将访问所有子对象,然后为self调用drawRect,子对象的访问方式也与子对象的访问方式相同,并且为每个第一级子对象调用drawRect,如中所示: -(void) processV

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

但事实证明,似乎每1/60秒,整个树就被遍历一次。从俯视图对象开始,iOS将访问所有子对象,然后为
self
调用
drawRect
,子对象的访问方式也与子对象的访问方式相同,并且为每个第一级子对象调用
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
}
每1/60秒就会有一个电话

processViewObject(topViewObject);    //  start from the topmost view object
因此,任何视图都可以在
drawRect
中绘制自身,并且如果视图的子视图的任何位置坐标被修改,或者其内容被更改,则脏位
needsUpdateNot
已提前设置,因此将调用它们的
drawRect
来重新绘制自身

或者实际上,如果设置了视图的脏位,则该位可能会在递归中传递给子级,如中所示:

    foreach children "c" already sorted by zOrder from 1 to the greatest number
        processViewObject(c, [self needsUpdateOrNot])
因此,如果设置了父对象的脏位,则还需要重新绘制子对象,以便正确绘制此视图中的整个图片

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

这就是在屏幕上绘制所有内容的整体机制吗?我听说过“永远不要调用
drawRect
我们自己,但让它被调用”,但我从来没有完全理解为什么,但如果以上是整体机制,那么看起来这就是原因

我想知道这是否与微软Windows或任何GUI操作系统上的机制几乎相同,在一些游戏框架上,我认为无论是否设置了脏的部分,所有内容都被绘制出来,因为据推测,游戏中的东西一直在移动,框架只需每隔1/60秒画出所有的图像

上面的
zOrder
处理顺序是在某个框架的代码中,因此首先绘制所有负zOrder子项,然后绘制
self
,然后绘制所有正zOrder子项。(这就是zOrder是如何通过在屏幕上绘制事物的画家模型方式实现的——后一种绘制方式将覆盖前一种绘制方式。)因此,
self
是一个zOrder,如果与子对象相关,
self
的zOrder数与它自己的兄弟对象相关,而不是与它的子对象相关


上述数据准确吗?如果给出答案,如果可能的话,是否可以引用部分源代码或参考资料,以便我们知道它是如何工作的标准或官方方式?

视图是从底部(z方向)向上绘制的。不透明视图等有各种优化。所有标记为脏的视图都会在运行循环结束时重新绘制-没有您怀疑的每1/60秒机制

参考:来自jrturton引用的

在iOS和Mac OS X中绘图遵循两种技术路径之一,并且是 基于视图按需更新其外观的模型

我认为这将解决定期更新视图的问题。视图只能按需更新,这是可以理解的,因为尽管iphone具有强大的处理能力,但它仍然是一款嵌入式设备。处理器/内存越少越好。。它还必须考虑电池寿命

更新视图时的某些情况(来自文档 (再次)

  • 用户移动或删除部分遮挡另一视图的视图
  • 用户从包含滚动的视图中滚动一个视图,然后将其重新滚动
  • 代码通过将以前隐藏的视图的hidden属性设置为NO,使其再次可见
  • 代码显式使视图无效要使视图无效,从而将其标记为重绘,可以调用setNeedsDisplay或
    setNeedsDisplayInRect:在视图上
在主事件循环的一个周期结束时,窗口向下移动 它的视图层次结构和请求这些视图自己绘制 调用它们的drawRect:methods


所以在主事件循环中,窗口(即父窗口)遍历整个树层次结构,但只更新需要更新的子节点。。其他视图保持原样。

我认为您混淆了合成和绘图。这两个概念是不同的,它们在不同的地方发挥作用

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

当需要移动视图或对其应用简单变换(旋转、缩放等)时,不会重新绘制视图,只移动背景层并合成可见场景中的层。同样,每个视图和子视图都有自己的背景层,因此它们在视图(层)层次结构中按Z顺序合成。在GPU上进行合成是一项速度非常快的操作,远远快于视图的初始绘制。这就是在iOS中实现平滑滚动或动画的原因,因为这些底层矩形图像只是在G上移动