UIView/CALayer如何在没有drawRect:的情况下呈现自己



在苹果的核心动画文档中,它说有两个渲染路径。据我所知,CALayer缓存UIView内容的位图数据。有两种方式可以提供CAL层的内容。一种是实现drawRect:或其他CALayer绘制方法,另一种是为CALayer的属性内容设置位图。

我想知道,如果以上两件事都不做,幕后会发生什么?我相信UIView在这种情况下使用了一个私有绘图路径。这个专用绘图路径由什么组成?它是如何工作的?

CALayer的关键在于它有GPU支持。在现代图形和动画中,您希望最大限度地减少位图数据在CPU和GPU之间交叉的次数。这些操作成本高昂。

无论使用setContents:还是drawRect:,CALayer始终使用专用图形路径。事实上,CALayer的底层管道以基本相同的方式处理这两者。当你setContents:时,CALayer会获取你给它的图像,并通过OpenGL(可能是现在的Metal)调用将其上传到GPU。当您drawRect:时,CALayer会为您提供一个可以绘制的上下文,然后它会对位图数据执行同样的操作。

如果你不设置内容或实现drawRect,你仍然可以做一些事情,比如设置层的背景色、边界、角半径等。这是由CALayer基于GPU的专用绘制路径渲染的。

CALayer不使用drawRect:绘制其任何内容。只有基于视图的绘图技术(如Core Graphics)使用drawRect:但这种方法唯一的问题是它是在CPU和主线程上完成的,这使它成为一个昂贵的过程。因此,Core Animation直接在图形硬件中操纵应用程序内容的缓存位图,这一点要优化得多。您可以通过核心动画层的一个代理(displayLayer:或drawLayer:inContext)或使用您提到的contents属性来更新或提供核心动画层初始内容。核心动画中的所有层对象都源自CALayer。

CALayer只是一个属于Core Animation的层对象,它本身只是UIView或UIView子类的支持系统。核心动画不是一种绘图技术,因为它不能创建像Quartz、Open GL ES和Metal can这样的原始形状。相反,核心动画允许您操作现有的视图,它通过缓存UIView的位图数据并将其发送到要操作的图形硬件来实现这一点。我们说核心动画是一个支持系统,它的所有工作都依赖于使用层对象,其中CALayer是主要类型。当然,只有当视图有一个图层,而视图实际上不需要图层存在时,它才能做到这一点。然而,在iOS中,默认情况下,所有视图都附带一个层。我们说iOS中的视图是"层支持的"。在MacOS中,您需要实际添加对视图的核心动画支持。

实际绘制CALayer的内容有几种方式。第一个是更改CALayer的contents属性,正如您所提到的,您可以通过给它一个CGImageRef来实现这一点。第二种方法是在子类中实现或重写CALayer委托displayLayer:它创建一个位图并将其设置为层的内容属性。第三种方法是在子类中实现或重写CALayer delegate drawLayer:inContext,它创建一个位图,创建一个图形上下文以绘制到该位图中,然后调用您的delegate方法来填充位图。

在iOS中,我们通常不担心视图层的内容是如何渲染的。由于所有视图都是层支持的,iOS使用我刚才描述的方法来管理如何以最有效的方式渲染这些视图。这是一种优化,可以节省您的时间,并使图层非常易于使用。如果您正在为MacOS开发视图,而MacOS中的视图并不总是有层支持的,那么您通常会担心覆盖这些委托或将其子类化。如果您决定不在iOS中使用默认的CALayer,您也可能会担心这一点,例如,您可能会将视图的层从CALayer更改为CAMetalLayer。或者,如果您正在寻找性能优化,甚至在少数情况下也是如此。

向层提供内容有三种方法。 - Assign an image object directly to the layer object’s contents property. - Assign a delegate object to the layer and let the delegate draw the layer’s content. - Define a layer subclass and override one of its drawing methods to provide the layer contents yourself. 如果我们不实现drawRect:或设置contents属性或将层子类化,它将使用默认的方式,即第二种方式向支持层的视图的层提供内容。该层将捕获视图的内容并进行渲染

相关内容

最新更新