SwiftUI 自定义 List 不能在 ForEach 中使用 Binding
Posted
技术标签:
【中文标题】SwiftUI 自定义 List 不能在 ForEach 中使用 Binding【英文标题】:SwiftUI custom List cannot use Binding in ForEach 【发布时间】:2020-08-12 09:19:51 【问题描述】:我正在尝试构建一个自定义列表,用户可以在其中选择一个条目,该行将展开并显示一个选择器。这个选择器应该更新一个存储时间信息的对象(TimeItem)。
但是,我无法在 ForEach 循环中通过 Picker 使用绑定,我不知道为什么。 Xcode 中的错误消息是“编译器无法在合理的时间内对该表达式进行类型检查;请尝试将表达式分解为不同的子表达式”。
我还尝试使用ForEach(Array(items.enumerated()), id: \.1)
而不是ForEach(items)
来获取当前行的索引,但这会弄乱删除动画(但只是有时!?)。
我不想为每一行使用相同的绑定(例如self.$selectedElement.minutes
) - 每行都应该有自己的绑定。
有人知道如何解决这个问题吗?感谢您的帮助!
class TimeItem: Identifiable, Equatable, ObservableObject
static func == (lhs: TimeItem, rhs: TimeItem) -> Bool
lhs.id == rhs.id
let id = UUID()
@Published var minutes: Int = 0
@Published var seconds: Int = 30
struct ContentView: View
@State var items = [TimeItem]()
@State var selectedElement: TimeItem?
var body: some View
ScrollView()
VStack
ForEach(items) elem in
ZStack
Rectangle()
.cornerRadius(12)
.frame(height: elem == selectedElement ? 120 : 40)
.foregroundColor(Color.gray.opacity(0.15))
Text("\(elem.minutes)")
.opacity(elem == selectedElement ? 0 : 1)
.transition(AnyTransition.scale)
if(elem == selectedElement)
HStack
Picker(selection: elem.$minutes, label: Text("")) // <- I can't use Binding with "elem"
ForEach(0..<60) i in
Text("\(i)")
.frame(width: 120)
.clipped()
Picker(selection: .constant(0), label: Text(""))
ForEach(0..<60) i in
Text("\(i)")
.frame(width: 120)
.clipped()
.frame(height: 120)
.clipped()
HStack
Button(action:
self.items.removeAll $0.id == elem.id
)
Image(systemName: "minus.circle.fill")
.foregroundColor(Color.red)
.font(.system(size: 22))
.padding(.leading, 10)
Spacer()
.padding(.horizontal)
.padding(.top)
.contentShape(Rectangle())
.onTapGesture
withAnimation(.spring())
self.selectedElement = elem
Spacer()
Button(action:
self.items.append(TimeItem())
)
ZStack
Rectangle()
.cornerRadius(12)
.frame(height: 40)
.foregroundColor(Color.gray.opacity(0.15))
Text("Add")
HStack
Image(systemName: "plus.circle.fill")
.foregroundColor(Color.green)
.font(.system(size: 22))
.padding(.leading, 10)
Spacer()
.padding()
.animation(.spring(), value: items)
【问题讨论】:
【参考方案1】:你应该按照编译器所说的去做:将表达式(即大视图)分解为不同的子表达式(即较小的子视图)
这里是固定组件(使用 Xcode 11.4 / ios 13.4 测试)
struct ContentView: View
@State var items = [TimeItem]()
@State var selectedElement: TimeItem?
var body: some View
ScrollView()
VStack
ForEach(items) elem in
ItemRowView(elem: elem, selectedElement: self.$selectedElement)
self.items.removeAll $0.id == elem.id
Spacer()
AddItemView
self.items.append(TimeItem())
.animation(.spring(), value: items)
struct SelectedElementView: View
@ObservedObject var elem: TimeItem
var body: some View
HStack
Picker(selection: $elem.minutes, label: Text(""))
ForEach(0..<60) i in
Text("\(i)")
.frame(width: 120)
.clipped()
Picker(selection: .constant(0), label: Text(""))
ForEach(0..<60) i in
Text("\(i)")
.frame(width: 120)
.clipped()
.frame(height: 120)
.clipped()
struct AddItemView: View
let action: ()->()
var body: some View
Button(action: action)
ZStack
Rectangle()
.cornerRadius(12)
.frame(height: 40)
.foregroundColor(Color.gray.opacity(0.15))
Text("Add")
HStack
Image(systemName: "plus.circle.fill")
.foregroundColor(Color.green)
.font(.system(size: 22))
.padding(.leading, 10)
Spacer()
.padding()
struct ItemRowView: View
@ObservedObject var elem: TimeItem
@Binding var selectedElement: TimeItem?
let action: ()->()
var body: some View
ZStack
Rectangle()
.cornerRadius(12)
.frame(height: elem == selectedElement ? 120 : 40)
.foregroundColor(Color.gray.opacity(0.15))
Text("\(elem.minutes)")
.opacity(elem == selectedElement ? 0 : 1)
.transition(AnyTransition.scale)
if(elem == selectedElement)
SelectedElementView(elem: elem)
HStack
Button(action: action)
Image(systemName: "minus.circle.fill")
.foregroundColor(Color.red)
.font(.system(size: 22))
.padding(.leading, 10)
Spacer()
.padding(.horizontal)
.padding(.top)
.contentShape(Rectangle())
.onTapGesture
withAnimation(.spring())
self.selectedElement = self.elem
【讨论】:
有趣!谢谢你的帮助!我什至没有考虑将视图分解为子视图,因为对我来说,当代码出现其他问题时,通常会出现该错误消息。以上是关于SwiftUI 自定义 List 不能在 ForEach 中使用 Binding的主要内容,如果未能解决你的问题,请参考以下文章
iOS 16 中 SwiftUI 4.0 Toolbar 自定义背景色以及 List 自动编辑操作的原生支持
iOS 16 中 SwiftUI 4.0 Toolbar 自定义背景色以及 List 自动编辑操作的原生支持