如何让enum-case的兄弟构建自定义选择器



我正在尝试构建一个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)
}
}
}

最新更新