返回

如何在 SwiftUI LazyHStack 中仅重绘选定项目?优化性能指南

IOS

## 如何实现仅重绘 LazyHStack 中的选定项目

作为经验丰富的程序员和技术作家,我经常需要优化界面性能。在最近的一次项目中,我遇到了一个问题,即在 LazyHStack 中点击一个项目时,整个 hstack 都会被重新渲染。

### 问题

LazyHStack 是 SwiftUI 中的一种容器视图,它只渲染当前可见的项目。但是,在我遇到的问题中,每次我点击一个项目(在它周围绘制一个边框)时,整个 hstack 都会被重新绘制,包括其中的所有项目(我添加了调试彩虹以在视觉上看到它重新渲染)。

### 解决方案

经过一番调查,我发现了导致这一行为的几个原因,并找到了解决问题的办法。

#### 优化视图层次结构

第一个优化是将 MyItemView 声明为 @ViewBuilder。这是一个闭包,允许延迟视图的构建,直到它需要显示为止。这可以帮助减少在不需要时创建和销毁视图。

struct MyItemView: View {

    let model: MyModel
    @Binding var isSelected: Bool

    var body: some View {
        ZStack {
            // ...
        }
    }
}

#### 使用差异更新

第二个优化是使用 Diffable 协议来检测 MyModel 数组中的差异,并仅更新发生更改的视图。这可以减少对整个 LazyHStack 的不必要的重新渲染。

struct MyModel: Identifiable, Hashable {

    // ...
}
struct MySelectorView: View {

    // ...

    var body: some View {
        // ...
            .ForEach(viewModel.types, id: \.id) { model in
                // ...
            }
        // ...
    }
}

#### 避免不必要的更新

最后,我确保只有在 MyModel 的状态发生变化时才更新 MyItemView。例如,如果只有 isSelected 状态发生变化,则仅重新渲染该特定的 MyItemView

#### 优化后的代码

struct MyItemView: View {

    // ...
}

struct MySelectorView: View {

    // ...

    var body: some View {
        // ...
    }
}

通过实施这些优化,我能够显著减少 LazyHStack 的不必要的重新渲染,从而提高了应用程序的性能。

### 常见问题解答

1. 为什么 LazyHStack 会重新渲染整个 hstack

这是因为默认情况下,LazyHStack 会重新渲染其所有视图,即使只有其中的一个发生了变化。

2. Diffable 协议如何帮助减少重新渲染?

Diffable 协议允许 LazyHStack 检测 MyModel 数组中的差异,并仅更新发生更改的视图。

3. 我应该始终使用 ViewBuilder 吗?

ViewBuilder 对于优化延迟加载视图非常有用,但它并非总是必要的。如果视图结构很简单并且不会经常更改,那么使用 View 也没关系。

4. 如何避免不必要的更新?

确保仅在视图状态发生变化时才更新视图。可以通过使用 @State@Binding 等 SwiftUI 状态管理工具来实现这一点。

5. 我可以进一步优化 LazyHStack 性能吗?

有几种其他技术可以进一步优化 LazyHStack 性能,例如使用 FixedSizeList 或减少视图的复杂性。