SwiftUI 如何在 EditMode 更改时执行操作?

car*_*ram 7 list editmode swiftui

我想在 EditMode 更改时执行操作。

具体来说,在编辑模式下,用户可以选择一些项目进行删除。之后他通常会按下垃圾箱按钮。但他也可能按“完成”。当他稍后再次按“编辑”时,先前选择的项目仍处于选中状态。我希望清除所有项目。

struct ContentView: View {
    @State var isEditMode: EditMode = .inactive
    @State var selection = Set<UUID>()
    var items = [Item(), Item(), Item(), Item(), Item()]

    var body: some View {
        NavigationView {
            List(selection: $selection) {
                ForEach(items) { item in
                    Text(item.title)
                }
            }
            .navigationBarTitle(Text("Demo"))
            .navigationBarItems(
                leading: EditButton(),
                trailing: addDelButton
            )
            .environment(\.editMode, self.$isEditMode)
        }
    }

    private var addDelButton: some View {
        if isEditMode == .inactive {
            return Button(action: reset) {
                Image(systemName: "plus")
            }
        } else {
            return Button(action: reset) {
                Image(systemName: "trash")
            }
        }
    }

    private func reset() {
        selection = Set<UUID>()
    }
}
Run Code Online (Sandbox Code Playgroud)

物品定义:

struct Item: Identifiable {
    let id = UUID()
    let title: String

    static var i = 0
    init() {
        self.title = "\(Item.i)"
        Item.i += 1
    }
}
Run Code Online (Sandbox Code Playgroud)

car*_*ram 14

@Casper 为我指明了正确的方向。这是我想出的。此解决方案用一颗石头捕获 2 只鸟:

  1. 当 editMode 被切换时,整个视图会重绘自身
  2. 可以在激活/取消激活 editMode 时执行特定操作

希望这对其他人有帮助。

struct ContentView: View {
    @State var editMode: EditMode = .inactive
    @State var selection = Set<UUID>()
    @State var items = [Item(), Item(), Item()]

    var body: some View {
        NavigationView {
            List(selection: $selection) {
                ForEach(items) { item in
                    Text(item.title)
                }
            }
            .navigationBarTitle(Text("Demo"))
            .navigationBarItems(
                leading: editButton,
                trailing: addDelButton
            )
            .environment(\.editMode, self.$editMode)
        }
    }

    private var editButton: some View {
        Button(action: {
            self.editMode.toggle()
            self.selection = Set<UUID>()
        }) {
            Text(self.editMode.title)
        }
    }

    private var addDelButton: some View {
        if editMode == .inactive {
            return Button(action: addItem) {
                Image(systemName: "plus")
            }
        } else {
            return Button(action: deleteItems) {
                Image(systemName: "trash")
            }
        }
    }

    private func addItem() {
        items.append(Item())
    }

    private func deleteItems() {
        for id in selection {
            if let index = items.lastIndex(where: { $0.id == id }) {
                items.remove(at: index)
            }
        }
        selection = Set<UUID>()
    }
}
Run Code Online (Sandbox Code Playgroud)
extension EditMode {
    var title: String {
        self == .active ? "Done" : "Edit"
    }

    mutating func toggle() {
        self = self == .active ? .inactive : .active
    }
}
Run Code Online (Sandbox Code Playgroud)


Tre*_* M. 9

List我一直在尝试在用户退出时清除选择editMode。对我来说,我发现对以下变化做出反应的最干净的方式editMode

确保引用该@Environment变量:

@Environment(\.editMode) var editMode
Run Code Online (Sandbox Code Playgroud)

在视图中添加计算属性来监视状态:

private var isEditing: Bool {
   editMode?.wrappedValue.isEditing == true
}
Run Code Online (Sandbox Code Playgroud)

然后使用.onChange(of:perform:)方法:

.onChange(of: self.isEditing) { value in
  if value {
    // do something
  } else {
    // something else
  }
}
Run Code Online (Sandbox Code Playgroud)

全部一起:

struct ContentView: View {
  
  @Environment(\.editMode) var editMode
  @State private var selections: [String] = []
  @State private var colors: ["Red", "Yellow", "Blue"]

  private var isEditing: Bool {
    if editMode?.wrappedValue.isEditing == true {
       return true
     }
     return false
  }
  
  var body: some View {

    List(selection: $selections) {
      ForEach(colors, id: \.self) { color in
        Text("Color")
      }
    }
    .toolbar {
      ToolbarItem(placement: .navigationBarTrailing) {
        EditButton()
      }
    }
    .onChange(of: isEditing) { value in
      if value == false {
        selection.removeAll()
      }
    }
  }

}
Run Code Online (Sandbox Code Playgroud)