我正在尝试构建一个SwiftUI,它接受任何枚举大小写作为其选择,然后它将自动将其兄弟项呈现为选项。以下是我开始的内容,但我很难克服泛型:
enum Option: String, CaseIterable, Identifiable, Equatable {
case abc
case def
case ghi
var id: Self { self }
}
struct CustomPicker<Sources>: View where Sources: RawRepresentable & CaseIterable & Identifiable, Sources.AllCases: RandomAccessCollection, Sources.RawValue == String {
@Binding var selection: Sources.AllCases.Element
var body: some View {
ScrollView(.horizontal) {
HStack(spacing: 8) {
ForEach(Sources.allCases) { item in
Text(item.rawValue)
}
}
.padding(.horizontal)
}
}
}
当我尝试使用它时,我得到了一个编译错误:Generic parameter 'Sources' could not be inferred
:
enum Fruit: String, CaseIterable, Identifiable, Equatable {
case apple, banana, orange
}
struct ContentView: View {
@State private var selectedFruit: Fruit = .apple // Error here
var body: some View {
CustomPicker(selection: $selectedFruit) // Error here
}
}
如何使泛型正确,以便能够处理任何String/RawRepresentable枚举并自动构建其同级?
您的代码离实现预期结果不远了。一些评论:
- 您不需要要求
Sources
符合Identifiable
:它需要是Hashable
才能与ForEach
一起工作,然后强制ForEach
使用.self
作为id。枚举的原始值是String
类型(您需要它(,使用.self
总是有效的 - CCD_ 10不是CCD_
- 主视图正在传递
Fruit
,但选择器视图需要类型Sources.AllCases.Element
:它们不匹配。只需在@Binding
中使用Sources
即可 - 请记住更新
@Binding
的值
下面是一个工作示例:
struct ContentView: View {
@State private var selectedFruit: Fruit = .apple
@State private var selectedCar = Car.ferrari
var body: some View {
VStack {
CustomPicker(selection: $selectedFruit)
CustomPicker(selection: $selectedCar)
// Just for testing
Text("Eating one (selectedFruit.rawValue) in a (selectedCar.rawValue)")
.font(.largeTitle)
.padding()
}
}
}
// The Enum doesn't need to be Identifiable
enum Fruit: String, CaseIterable {
case apple, banana, orange
}
enum Car: String, CaseIterable {
case ferrari, porsche, jaguar, dacia
}
// Replace Identifiable with Hashable
struct CustomPicker<Sources>: View where Sources: RawRepresentable & CaseIterable & Hashable, Sources.AllCases: RandomAccessCollection, Sources.RawValue == String {
@Binding var selection: Sources // This is the right type
var body: some View {
ScrollView(.horizontal) {
HStack(spacing: 8) {
// Force the id as the item itself
ForEach(Sources.allCases, id: .self) { item in
Text(item.rawValue)
// Somehow you need to update the @Binding
.onTapGesture {
selection = item
}
}
}
.padding(.horizontal)
}
}
}