如何在 SwiftUI LazyHStack 中仅重绘选定项目?优化性能指南
2024-03-06 10:35:07
## 如何实现仅重绘 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
或减少视图的复杂性。