swiftui - 如何在 SwiftUI 中使用绑定元素来更新 ForEach 而无需渲染所有 ForEach 数组?
问题描述
我有一个颜色数组,我使用这个数组多次渲染一个视图,这个数组的每个元素都有一个与绑定一起工作的视图的状态角色,所以我们有一个作为状态数组的数组,每个该数组的单个元素将用于提供需要绑定的视图,代码可以正常工作,但是对该数组的每一次小更新都会使 ForEach 渲染所有数组,这是不必要的,我想更正或修改我的代码以停止这种情况不必要的渲染!例如,当我将 1 个元素更改为 Color.black 时,SwiftUI 为该元素呈现一个新视图是可以理解的,但事实上我的代码使 SwiftUI 呈现所有数组!或者当我将新元素添加到数组末尾时,也会发生同样的事情!我怎么解决这个问题?谢谢。
PS:如果你认为index或id:.self会造成这个问题,我不得不说不,因为我必须而且我必须使用 index,因为 Binding 需要一个 State 对象,并且只能使用 index,我不能使用ForEach 的 item 版本,因为 Binding 无法更新它。
var randomColor: Color { return Color(red: Double.random(in: 0...1), green: Double.random(in: 0...1), blue: Double.random(in: 0...1)) }
struct BindingWay: View {
@State private var arrayOfColor: [Color] = [Color]()
var body: some View {
VStack(spacing: 0) {
ForEach(arrayOfColor.indices, id:\.self) { index in
CircleViewBindingWay(colorOfCircle: $arrayOfColor[index])
}
Spacer()
Button("append new Color") {
arrayOfColor.append(randomColor)
}
.padding(.bottom)
Button("update last element color to black") {
if arrayOfColor.count > 0 {
arrayOfColor[arrayOfColor.count - 1] = Color.black
}
}
.padding(.bottom)
}
.shadow(radius: 10)
}
}
struct CircleViewBindingWay: View {
@Binding var colorOfCircle: Color
init(colorOfCircle: Binding<Color>) { print("initializing CircleView"); _colorOfCircle = colorOfCircle }
var body: some View {
print("rendering CircleView")
return Circle()
.fill(colorOfCircle)
.frame(width: 50, height: 50, alignment: .center)
.onTapGesture { colorOfCircle = colorOfCircle.opacity(0.5) }
}
}
解决方案
以下作品:
struct CircleViewBindingWay: View {
@Binding var colorOfCircle: Color
init(colorOfCircle: Binding<Color>) { print("initializing CircleView"); _colorOfCircle = colorOfCircle }
var body: some View {
print("rendering CircleView")
return Circle()
.fill(colorOfCircle)
.frame(width: 50, height: 50, alignment: .center)
.onTapGesture { colorOfCircle = colorOfCircle.opacity(0.5) }
}
}
extension CircleViewBindingWay : Equatable { //<-- here
static func == (lhs: CircleViewBindingWay, rhs: CircleViewBindingWay) -> Bool {
lhs.colorOfCircle == rhs.colorOfCircle
}
}
struct ContentView: View {
@State private var arrayOfColor: [Color] = [Color]()
var randomColor: Color { return Color(red: Double.random(in: 0...1), green: Double.random(in: 0...1), blue: Double.random(in: 0...1)) }
var body: some View {
VStack(spacing: 0) {
ForEach(arrayOfColor.indices, id: \.self) { index in
CircleViewBindingWay(colorOfCircle: .init(get: { () -> Color in //<-- here
arrayOfColor[index]
}, set: { (newValue) in
arrayOfColor[index] = newValue
}))
}
Spacer()
Button("append new Color") {
arrayOfColor.append(randomColor)
}
.padding(.bottom)
Button("update last element color to black") {
if arrayOfColor.count > 0 {
arrayOfColor[arrayOfColor.count - 1] = Color.black
}
}
.padding(.bottom)
}
.shadow(radius: 10)
}
}
必须发生的事情:
CircleViewBindingWay
符合Equatable
并检查颜色是否相同。ForEach
equatable 检查本身,这就是为什么实际上.equatable()
不需要附加被
Binding
声明为内联。必须有另一个相等的检查ForEach
/SwiftUI
对$arrayOfColor
失败的检查,但是这个内联检查通过了。
推荐阅读
- laravel - Laravel:将当前视图名称传递给 View Composer
- php - Unserialize() 不适用于特定数据
- peoplesoft - 选择行时从网格触发人员代码
- c++ - 无法使用 LoadLibrary 函数加载 dll 文件
- apache-poi - 如何通过apache poi向单词表添加评论
- php - 使用 Laravel 护照和 Vuejs。尽管用户已通过身份验证,但 Auth::User() 在刀片上不起作用
- python - setup.py 与命名空间包中的 cython 编译:* .pxd 未找到
- c++ - LLJIT 运行错误“分段错误:11”,同时链接 C++ 标准库
- jquery - 单击多选时删除选项的蓝色
- jquery - 如何使用 jQuery 将现有的输入文本添加到动态创建的表单中?