SwiftUI:启用高性能 Metal 渲染

SwiftUI默认使用Core Animation进行渲染,提供了出色的开箱即用性能。但是,对于复杂的渲染,您可能会发现代码开始变慢——任何低于每秒60帧(FPS)的问题都是一个问题,但实际上您应该将目标更高,因为许多iOS设备现在以120fps的速度渲染。

为了说明这一点,让我们看一些示例代码。我们将创建一个颜色循环视图,以各种颜色呈现同心圆。结果看起来像是一个径向渐变,但我们将添加两个属性以使其更具可定制性:一个用于控制应绘制多少个圆,另一个用于控制颜色循环——它将能够移动渐变周围的开始和结束颜色。

我们可以通过使用Color(hue:saturation:brightness:)初始值设定项来获得颜色循环效果:hue 是从0到1的值,控制着我们所看到的颜色的种类——红色是0到1,所有其他色相都介于两者之间。为了弄清楚特定圆圈的色相,我们可以取圆圈数(例如25),除以圆圈数(例如100),然后加上颜色循环量(例如0.5)。因此,如果我们是100的第25圈,循环量为0.5,则我们的色相将为0.75。

这里的一个小复杂性是,色相在达到1.0后不会自动换行,这意味着1.0的色相等于0.0的色相,但是1.2的色相不等于0.2的色相。因此,我们将手工包裹色相:如果色相超过1.0,我们将减去1.0,以确保它始终位于0.0到1.0的范围内。

这是代码:

struct ColorCyclingCircle: View {
    var amount = 0.0
    var steps = 100

    var body: some View {
        ZStack {
            ForEach(0.. Color {
        var targetHue = Double(value) / Double(self.steps) + self.amount

        if targetHue > 1 {
            targetHue -= 1
        }

        return Color(hue: targetHue, saturation: 1, brightness: brightness)
    }
}

现在,我们可以在布局中使用它,将其颜色循环绑定到由滑块控制的局部属性:

struct ContentView: View {
    @State private var colorCycle = 0.0

    var body: some View {
        VStack {
            ColorCyclingCircle(amount: self.colorCycle)
                .frame(width: 300, height: 300)

            Slider(value: $colorCycle)
        }
    }
}

如果您运行该应用程序,将会看到我们有一个整齐的彩色波浪效果,完全可以通过在滑块上拖动来控制,并且效果非常流畅。

简单视图.gif

您现在所看到的是由Core Animation驱动的,这意味着它将把我们的100个圆变成在屏幕上绘制的100个独立视图。这在计算上是昂贵的,但是如您所见,它运行良好——我们获得了平稳的性能。

但是,如果稍微增加复杂度,我们会发现事情并不是那么乐观。用以下一个替换现有的strokeBorder()修饰符:

.strokeBorder(LinearGradient(gradient: Gradient(colors: [
    self.color(for: value, brightness: 1),
    self.color(for: value, brightness: 0.5)
]), startPoint: .top, endPoint: .bottom), lineWidth: 2)

现在,这将呈现一个柔和的渐变,在圆的顶部显示明亮的颜色,在底部显示较暗的颜色。现在,当您运行该应用程序时,您会发现它运行起来要慢得多——SwiftUI正在努力为100个单独视图渲染100个渐变。


卡顿.gif

我们可以通过应用一个称为drawingGroup()的新修改器来解决此问题。这告诉SwiftUI,在将视图内容作为单个呈现的输出放回到屏幕上之前,应将视图的内容呈现到屏幕外的图像中(离屏渲染),这要快得多。在幕后,该功能由Metal提供支持,Metal是Apple的框架,可直接与GPU协同工作以实现极快的图形。

因此,将ColorCyclingCircle主体修改为此:

var body: some View {
    ZStack {
        // existing code…
    }
    .drawingGroup()
}

现在,再次运行它——仅需添加一点点,就可以正确渲染所有内容,即使使用渐变色,我们也可以全速返回。


SwiftUI:启用高性能 Metal 渲染_第1张图片
Metal 渲染.gif

重要提示:drawingGroup()修饰符有助于了解和保留您的武器库,这是解决性能问题的一种方法,但是您不应该经常使用它。添加屏幕外渲染过程可能会降低SwiftUI进行简单绘图的速度,因此,在尝试引入drawingGroup()之前,应等到遇到实际性能问题后再进行操作。

译自 Enabling high-performance Metal rendering with drawingGroup()

SwiftUI: 使用 ImagePaint 制作边框和填充 Hacking with iOS: SwiftUI Edition SwiftUI:特殊效果 - 模糊,混合模式等

赏我一个赞吧~~~

你可能感兴趣的:(SwiftUI:启用高性能 Metal 渲染)