列表选择为Set <String>-如何使用?

时间:2019-12-27 15:19:32

标签: swift swiftui swiftui-list

我正在玩SwiftUI,显然没有得到它。

有效的示例,仅显示所选名称。

struct ContentView: View {
    let names = ["Joe", "Jim", "Paul"]

    @State var selectedName = Set<String>()

    var body: some View {
        VStack {
            List(names, id: \.self, selection: $selectedName) { name in
                Text(name)
            }
            if !selectedName.isEmpty {
                Text(selectedName.first!) // <-- this line
            }
        }
    }
}

我想要的是一个可以更改名称的文本字段。尝试了很多方法,但是每次都会遇到另一个错误。

TextField("Name", text: $selectedName)
  

给出此错误:无法将类型'Binding >'的值转换为预期的参数类型'Binding '

TextField("Name", text: $selectedName.first!)
  

不能强制打开非可选类型'Binding <(((String)throws-> Bool)throws-> String?>''

我该怎么做?

3 个答案:

答案 0 :(得分:0)

很显然,您无法将Binding<Set<String>>传递给Binding<String>。这里给出了一个使用TextField更改selectedName变量的想法或解决方案:

我添加了一个新变量Binding<String>。然后,在TextField的onCommit闭包中更改selectedName。

struct ContentView: View {

let names = ["Joe", "Jim", "Paul"]

@State var selectedName = Set<String>()
@State var textFieldName = ""

var body: some View {
    VStack {
        List(names, id: \.self, selection: $selectedName) { name in
            Text(name)
        }
        if !selectedName.isEmpty {
            Text(selectedName.first!)
        }

        Text(textFieldName)

        TextField("Name", text: $textFieldName, onEditingChanged: { (Bool) in
            //onEditing
        }) {
            //onCommit
            self.selectedName.insert(self.textFieldName)
        }
    }
  }
}

答案 1 :(得分:0)

您可以自己进行绑定:

 TextField("Name", text: Binding<String>(get: {self.selectedName.first!}, set: { _ in}) )

答案 2 :(得分:0)

好的,如果我需要编辑一个屏幕中的names值,并列出并编辑字段,并使它们全部同步而不彼此混淆,这是我的替代方法。

这里是完整的可测试模块(已在Xcode 11.2 / iOS 13.2上测试)。当我在iOS上进行测试时,API要求将List放入EditMode来处理选择,因此包括在内。

struct TestChangeSelectedItem: View {
    @State var names = ["Joe", "Jim", "Paul"] // made modifiable
    @State var selectedName: String? = nil // only one can be edited, so single selection

    @State var editMode: EditMode = .active // Tested for iOS, so it is needed

    var body: some View {
        VStack {
            List(selection: $selectedName) {
                ForEach(names, id: \.self) { name in
                    Text(name)
                }
            }
            .environment(\.editMode, $editMode) // Tested for iOS, so it is needed

            if selectedName != nil {
                Divider()
                Text(selectedName!) // Left to see updates for selection
                editor(for: selectedName!) // Separated to make more clear
            }
        }
    }

    private func editor(for selection: String) -> some View {
        let index = names.firstIndex(of: selection)!
        var editedValue = selection // local to avoid cycling in refresh

        return HStack {
            Text("New name:")
            TextField("Name", text: Binding<String>(get: { editedValue }, set: { editedValue = $0}), onCommit: {
                self.names[index] = editedValue
                self.selectedName = editedValue
            })
        }
    }
}

struct TestChangeSelectedItem_Previews: PreviewProvider {
    static var previews: some View {
        TestChangeSelectedItem()
    }
}