UIView/CALayer如何在没有drawRect()的情况下渲染自己?

3
在苹果的核心动画文档中,它说有两个渲染路径。据我所知,CALayer缓存了UIView内容的位图数据。提供CALayer内容有两种方法。一种是实现drawRect:或其他CALayer绘制方法,另一种是将位图设置为CALayer的contents属性。
在这里,我想知道,如果以上两种情况都没有发生,背后会发生什么?我相信在这种情况下,UIView使用了一个私有的绘制路径。这个私有的绘制路径包括什么?它是如何工作的?
3个回答

2
CALayer不使用drawRect:来绘制其任何内容。只有基于视图的绘制技术,如核心图形,才使用drawRect:,但这种方式的唯一问题是它在CPU和主线程上执行,使其成为昂贵的过程。因此,Core Animation直接在图形硬件中操作应用程序内容的缓存位图,这样更加优化。您可以通过其中一个委托(displayLayer:或drawLayer:inContext)或使用contents属性更新或提供Core Animation层的初始内容,就像您已经提到的那样。Core Animation中的所有层对象都源自CALayer。
CALayer只是属于Core Animation的图层对象,而Core Animation本身只是UIView或UIView子类的支持系统。Core Animation不是一种绘图技术,因为它不能创建原始形状,例如Quartz、Open GL ES和Metal。相反,Core Animation允许您操作已经存在的视图,并通过缓存UIView的位图数据并将其发送到图形硬件来完成此操作。我们说Core Animation是一个支持系统,其所有工作都依赖于使用层对象,其中CALayer是主要类型。当然,只有当视图具有图层时,它才能执行此操作,而实际上视图并不需要存在图层。但是,在iOS中,所有视图默认附带图层。我们说iOS中的视图是“layer backed”。在MacOS中,您需要为视图实际添加Core Animation支持。
CALayer的内容实际绘制有几种方式。第一种是像您提到的那样更改CALayer的contents属性,并通过给它一个CGImageRef来完成此操作。第二种是通过在子类中实现或覆盖CALayer委托displayLayer:,该委托创建位图并将其设置为图层的内容属性。第三种是通过在子类中实现或覆盖CALayer委托drawLayer:inContext,该委托创建位图,创建用于绘制位图的图形上下文,然后调用您的委托方法以填充位图。
在iOS中,我们通常不必担心如何渲染视图层的内容。由于所有视图都是“layer backed”,因此iOS会使用我刚才描述的方法来管理如何以最有效的方式呈现这些视图。这是一种优化,可节省您的时间,并使图层非常易于使用。如果您正在开发MacOS,则通常会担心覆盖这些委托或对其进行子类化,因为视图并不总是具有图层支持。如果您决定不使用iOS中的默认CALayer,例如,您可能会将视图的图层从CALayer更改为CAMetalLayer。或者,如果您正在寻找性能优化,甚至在极少数情况下也可能会担心这个问题。

2
CALayer的关键在于它是由GPU支持的。在现代图形和动画中,您需要尽量减少位图数据在CPU和GPU之间传输的次数。这些操作是昂贵的。
无论您是使用setContents还是drawRect,CALayer总是使用私有绘图路径。实际上,CALayer的基础管道以基本相同的方式处理这两个方法。当您使用setContents时,CALayer会获取您提供的图像,并通过OpenGL(现在可能是Metal)调用将其上传到GPU。当您使用drawRect时,CALayer会向您提供一个上下文,您可以在其中进行绘制,然后它会对位图数据执行相同的操作。
如果您没有设置内容或实现drawRect,则仍然可以执行一些操作,例如设置图层的背景颜色、边框、圆角等。这是由CALayer的基于GPU的私有绘图路径呈现的。

抱歉晚了,我的账户刚刚才恢复。在我提问后,我一直在学习iOS图形系统的工作原理,现在我已经知道了。 - user2002976

0

提供内容到一个层有三种方法:- 直接将图像对象分配给层对象的内容属性。- 将委托对象分配给层并让委托绘制层的内容。- 定义一个层子类并覆盖其绘图方法之一以自己提供层内容。如果我们不实现drawRect:或设置contents属性或子类化图层,则它将使用默认方式,即第二种方式来向具有层支持的视图的图层提供内容。该层将捕获视图的内容并呈现它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接