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

Posted

技术标签:

【中文标题】列表选择为 Set<String> - 如何使用?【英文标题】:List selection as Set<String> - how to use? 【发布时间】:2019-12-27 15:19:32 【问题描述】:

我在玩 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 Bool) throws -> String?>'的值

我该怎么做?

【问题讨论】:

【参考方案1】:

您可以自行绑定:

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

【讨论】:

非常感谢!我到处寻找所有解决方案,您的解决方案是最好的!【参考方案2】:

显然你不能将Binding&lt;Set&lt;String&gt;&gt; 传递给Binding&lt;String&gt;。这里为您提供了使用 TextField 更改 selectedName 变量的想法或解决方案:

我添加了一个新变量 Binding&lt;String&gt;。然后我在 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)
        
    
  

【讨论】:

【参考方案3】:

好的,如果我需要在一个屏幕中编辑 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()
    

【讨论】:

以上是关于列表选择为 Set<String> - 如何使用?的主要内容,如果未能解决你的问题,请参考以下文章

C# 从 List<T> 中选择存在于另一个列表中的所有元素

如何在Set的Assertj Collection中验证

两个List属性,无法使用LINQ创建列表

Java 将 Map<String,Set<String>> 转换为 Map<String,Set<Object1>> [关闭]

在这种情况下如何将集合转换为列表

快速将填充的 Set<String> 转换为 [String] [重复]