带有 @Binding 控件的 SwiftUI 动态列表

Posted

技术标签:

【中文标题】带有 @Binding 控件的 SwiftUI 动态列表【英文标题】:SwiftUI dynamic List with @Binding controls 【发布时间】:2019-09-07 19:48:36 【问题描述】:

如何使用@Binding 驱动的控件构建动态列表,而无需手动引用数组?这似乎很明显,但使用 List 或 ForEach 遍历数组会产生各种奇怪的错误。

struct OrderItem : Identifiable 
    let id = UUID()
    var label : String
    var value : Bool = false


struct ContentView: View 
    @State var items = [OrderItem(label: "Shirts"),
                        OrderItem(label: "Pants"),
                        OrderItem(label: "Socks")]
    var body: some View 
        NavigationView 
            Form 
                Section 
                    List 
                        Toggle(items[0].label, isOn: $items[0].value)
                        Toggle(items[1].label, isOn: $items[1].value)
                        Toggle(items[2].label, isOn: $items[2].value)
                    
                
            .navigationBarTitle("Clothing")
        
    

这不起作用:

            ...
                Section 
                    List($items, id: \.id)  item in
                        Toggle(item.label, isOn: item.value)
                    
                
            ...

类型“_”没有成员“id”

也没有:

            ...
                Section 
                    List($items)  item in
                        Toggle(item.label, isOn: item.value)
                    
                
            ...

无法推断通用参数“SelectionValue”

【问题讨论】:

解决这个问题可以实现更大的目标:要创建一个可以接受 $items 和管理的 ToggleList 视图,请显示切换。 【参考方案1】:

试试类似的东西

...
   Section 
       List(items.indices)  index in
           Toggle(self.items[index].label, isOn: self.$items[index].value)
       
   
...

【讨论】:

哇。不敢相信我错过了。我希望我能够传递一个实际的对象,但这会让我到达我需要去的地方。谢谢! 我不敢相信!!它确实有效。为什么这会起作用而传递对象却不起作用??!! 当数组中的项目数量稍后减少时,这种方法似乎会中断。见***.com/questions/57631225/…【参考方案2】:

虽然 Maki 的回答有效(在某些情况下)。它不是最佳的,它是discouraged by Apple。相反,他们在 WWDC 2021 期间提出了the following solution:

只需将绑定到您的集合传递到列表中,使用 普通的美元符号运算符,SwiftUI 会将绑定传回给 闭包中的每个单独元素。

像这样:

struct ContentView: View 
    @State var items = [OrderItem(label: "Shirts"),
                        OrderItem(label: "Pants"),
                        OrderItem(label: "Socks")]

    var body: some View 
        NavigationView 
            Form 
                Section 
                    List($items)  $item in
                        Toggle(item.label, isOn: $item.value)
                    
                
            .navigationBarTitle("Clothing")
        
    

【讨论】:

有趣。这是否仅限于新的 API? 根据 Matt Ricketson 的说法:“您甚至可以将此代码反向部署到 SwiftUI 支持的任何先前版本”。事实上,我认为它使用了 SE-0293 的一个特性(在 Swift 5.5 中实现)。但仅在旧的(v12)Xcode 中安装 5.5 工具链是不够的。我认为您还需要将 init(projectedValue:) 添加到 Binding 并使其符合 RandomAccessCollection 以便将此调整与旧版本的 SwiftUI 一起使用。

以上是关于带有 @Binding 控件的 SwiftUI 动态列表的主要内容,如果未能解决你的问题,请参考以下文章

当从 GeometryReader 中进行更改时,SwiftUI 不会反映对 @Binding @State 变量的更改

SwiftUI如何在View在初始化程序中需要@Binding时实例化PreviewProvider

Core Data + SwiftUI:无法将“Bool”类型的值转换为预期的参数类型“Binding<Bool>”

SwiftUI 验证和否决用户输入

SWIFTUI List 希望在列表中有切换。无法将“MyModel”类型的值转换为预期的参数类型“Binding<MyModel>”

WPF实现鼠标拖动控件并带有中间动效