SwiftUI 表单选取器选项未选择

SwiftUI Form Picker options are not selecting

提问人:Prasad De Zoysa 提问时间:10/2/2023 最后编辑:Prasad De Zoysa 更新时间:10/2/2023 访问量:86

问:

为什么我无法从此选取器视图中选择项?这里的区别在于我的选择数组由两个不同的结构体('CustomOptionOne'和'CustomOptionTwo')组成,它们符合相同的协议'PickerOption'。编译器给了我两个错误,

类型“any PickerOption”不能符合“Hashable”

静态方法“buildExpression”要求“Content”符合 “辅助功能转子内容”

我怎样才能做到这一点?

任何帮助将不胜感激。

protocol PickerOption: Hashable, Identifiable {
    var name: String { get set }
    var description: String { get set }
    var id: String { get }
}

struct MyView: View {
    
    //I know it's this line, but my array will consist of any object that conforms to PickerOption protocol
    private static var exampleStructs: [any PickerOption] = [
        CustomOptionOne(name: "Example 1", description: "Example Name 1", id: "5"),
        CustomOptionOne(name: "Example 2", description: "Example Name 2", id: "6"),
        CustomOptionTwo(name: "Example 3", description: "Example Name 3", id: "7"),
        CustomOptionTwo(name: "Example 4", description: "Example Name 4", id: "8")
    ]
    
    private struct CustomOptionOne: Hashable, Identifiable, PickerOption {
        var name: String
        var description: String
        var id: String
    }
    
    private struct CustomOptionTwo: Hashable, Identifiable, PickerOption {
        var name: String
        var description: String
        var id: String
    }
    
    @State private var selectedStruct: any PickerOption = CustomOptionOne(name: "Example Name", description: "Example Description", id: "9")
    
    var body: some View {
        
        NavigationView {
            Form {
                Section(header: Text("Selected Struct")) {
                    Text(selectedStruct.name)
                    Text(selectedStruct.description)
                }
                
                Section(header: Text("Picker")) {
                    Picker(selection: $selectedStruct, label: Text(selectedStruct.name), content: {
                        ForEach(MyView.exampleStructs, id: \.id) { exampleStruct in
                            Text(exampleStruct.name).tag(exampleStruct)
                        }
                    })
                }
            }
        }
    }
}

我已经检查了许多答案,包括这个快速选择器没有选择项目,但没有一个回答我的用例场景。

iOS SwiftUI swiftUI-picker

评论

0赞 Timmy 10/2/2023
要传递到的值的类型应与 selection 属性的类型匹配。所以你需要通过而不是.这回答了你的问题吗?Swift Picker 未选择项目tagexampleStructexampleStruct.id
0赞 Prasad De Zoysa 10/2/2023
传递“exampleStruct”会给出此编译错误Static method 'buildExpression' requires that 'Content' conform to 'AccessibilityRotorContent'
0赞 lorem ipsum 10/2/2023
id 不是 strict/object,标签类型需要与选择类型匹配
0赞 Prasad De Zoysa 10/2/2023
@loremipsum检查我更新的问题,它仍然不起作用。
0赞 lorem ipsum 10/2/2023
你最好使用 id 而不是结构,但 SwiftUI 以不使用存在论而闻名,所以你可能需要强制 ID 是带有 typealias 的字符串或我在协议中的定义

答:

1赞 lorem ipsum 10/2/2023 #1

对于 the 和 must 是完全相同的类型,您的特定示例增加了额外的复杂性,因为您正在尝试将 existentials () 与 SwiftUI 一起使用。Pickertagselectionany

因此,最简单的解决方案是同时使用 for 和 ,但首先您必须将 which comes from 限制为特定类型,以便您可以将其匹配为IDselectiontagIDIdentifiablePicker

protocol PickerOption: Hashable, Identifiable where ID == String {
    var name: String { get set }
    var description: String { get set }
    var id: String { get }
}

然后更改属性以使用String

@State private var selectedStructId: String? = nil

然后更改以匹配tagselectedStructId

Text(exampleStruct.name).tag(exampleStruct.id as String?)

整个事情放在一起看起来会是这样的

struct ContentView: View {
    
    //I know it's this line, but my array will consist of any object that conforms to PickerOption protocol
    private static var exampleStructs: [any PickerOption] = [
        CustomOptionOne(name: "Example 1", description: "Example Name 1", id: "5"),
        CustomOptionOne(name: "Example 2", description: "Example Name 2", id: "6"),
        CustomOptionTwo(name: "Example 3", description: "Example Name 3", id: "7"),
        CustomOptionTwo(name: "Example 4", description: "Example Name 4", id: "8")
    ]
    
    private struct CustomOptionOne: PickerOption {
        var name: String
        var description: String
        var id: String
    }
    
    private struct CustomOptionTwo: PickerOption {
        var name: String
        var description: String
        var id: String
    }
    
    @State private var selectedStructId: String? = nil
    
    var body: some View {
        NavigationStack {
            Form {
                if let selectedStructId, let selectedStruct = ContentView.exampleStructs.filter({ o in
                    o.id == selectedStructId
                }).first{ //Find the selected selected struct
                    Section(header: Text("Selected Struct")) {
                        Text(selectedStruct.name)
                        Text(selectedStruct.description)
                    }
                }
                Section(header: Text("Picker")) {
                    Picker(selection: $selectedStructId, label: Text(""), content: {
                        Text("Select an object.")
                        ForEach(ContentView.exampleStructs, id: \.id) { exampleStruct in
                            Text(exampleStruct.name).tag(exampleStruct.id as String?)

                        }
                    })
                }
            }
        }
    }
}

我知道这并不理想,但存在主义是与 SwiftUI 的一场艰苦战斗。

评论

0赞 Prasad De Zoysa 10/4/2023
正如你所承认的,这不是一个理想的解决方案。我希望在不从源数组中执行查找的情况下获取所选对象。但是,我知道我们目前没有其他关于存在主义的解决方案。我会接受这个答案,因为它确实在一定程度上解决了原来的问题。谢谢你的努力。