【问题标题】:How does a UIView/CALayer render itself without drawRect:?UIView/CALayer 如何在没有 drawRect: 的情况下呈现自己?
【发布时间】:2017-06-28 09:27:36
【问题描述】:

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

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

【问题讨论】:

    标签: ios uiview core-animation calayer


    【解决方案1】:

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

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

    如果你不设置内容或实现drawRect,你仍然可以设置图层的背景颜色、边框、圆角半径等。这是由CALayer基于GPU的私有绘图路径渲染的。

    【讨论】:

    • 抱歉迟到了。刚刚把我的账号找回来了。在我提出这个问题后,我一直在学习 iOS 图形系统的工作原理,现在我知道了。
    【解决方案2】:

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

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

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

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

    【讨论】:

      【解决方案3】:

      可以通过三种方式向图层提供内容。 - 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 属性或子类化图层,它将使用默认方式,即第二种方式为支持图层的视图的图层提供内容。该层将捕获视图的内容并进行渲染。

      【讨论】:

        猜你喜欢
        • 2013-10-10
        • 1970-01-01
        • 2020-09-22
        • 2013-06-21
        • 1970-01-01
        • 1970-01-01
        • 2014-04-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多