SwiftUI 从列表中编辑结构

Posted

技术标签:

【中文标题】SwiftUI 从列表中编辑结构【英文标题】:SwiftUI Edit Struct from List 【发布时间】:2020-11-05 12:41:58 【问题描述】:

我正在尝试创建一个列表,当它点击一个单元格时,它会更改 State 对象本身内的 hasBeenSeen Bool 值。

struct State: Identifiable 
    var id = UUID()
    let name: String
    var hasBeenSeen: Bool = false


struct ContentView: View 
    let states: [State] = [
        State(name: "Oregon", hasBeenSeen: true),
        State(name: "California", hasBeenSeen: true),
        State(name: "Massachussets", hasBeenSeen: false),
        State(name: "Washington", hasBeenSeen: true),
        State(name: "Georgia", hasBeenSeen: false)
    ]
    
    var body: some View 
        NavigationView 
            List 
                ForEach(states, id: \.id)  state in
                    StateCell(state: state)
                
            .navigationBarTitle(Text("States"))
        
    


struct StateCell: View 
    var state: State
    
    var body: some View 
        HStack 
            Text(state.name)
            Spacer()
            if state.hasBeenSeen 
                Image(systemName: "eye.fill")
            
        .onTapGesture 
//            state.hasBeenSeen.toggle()
        
    

我最初的想法是我需要将hasBeenSeen 变为@State var,但这似乎不起作用。我怎样才能使这个Bool val 可以从列表中编辑?

【问题讨论】:

【参考方案1】:

SwiftUI 中的视图是不可变的——它们只是结构——所以你不能改变它们的属性。这就是为什么 SwiftUI 有一个 @State 属性包装器的概念。当您更改“状态”属性时,SwiftUI 实际上会更新状态值,而不是视图的属性值(这也是不可变的)。

因此,您需要在视图中的 states 属性上设置 @State。 (您还需要更改名称,因为标识符 State 已被 State 属性包装器占用 - 所以我只是将其更改为 StateEntity

@State var states: [StateEntity] = [
      StateEntity(name: "Oregon", hasBeenSeen: true),
      // ... etc
   ]

但这还不够,因为当您将 states 数组的元素(StateEntity 值)传递给子视图时,您只是传递了一个副本。

为此,您需要一个绑定。绑定允许子视图修改父视图的状态属性,而无需拥有数据。因此,子视图的属性应该使用@Binding 属性包装器:

struct StateCell: View 
    @Binding var state: StateEntity

    // ...

SwiftUI 通过使用投影值(在本例中为$states)来轻松获取状态属性的绑定。

但是,您不需要将绑定传递给整个数组,而是传递给该数组的特定元素。不幸的是(而且相当烦人),这有点棘手。您需要获取元素的索引,并给定索引,像这样访问绑定:$state[index]

一种方法是对states 的索引执行ForEach

var body: some View 
   NavigationView 
      List 
         ForEach(states.indices)  index in
            StateCell(state: self.$states[index])
         
      .navigationBarTitle(Text("States"))
   

【讨论】:

以上是关于SwiftUI 从列表中编辑结构的主要内容,如果未能解决你的问题,请参考以下文章

如何从 SwiftUI 的详细信息视图(编辑项目视图)中删除核心数据条目?

从 SwiftUI 列表中的每个元素获取用户输入

如何以编程方式从 SwiftUI 列表中删除行并刷新列表视图?

SwiftUI - 如何在列表中编辑行?

是否可以在详细视图中编辑 SwiftUI 列表元素?

从 SwiftUI 中的工作表更新列表视图中的行