Hope my sample code explain the problem I'm facing: I want to make a SwiftUI.Picker view that choose value of a enum type conforming to Hashable, CaseIteratable
. Why this compile error? How to fix?
import SwiftUI
// Abstract type of value selectable via SwiftUI.Picker
protocol PickerEnum: Hashable, CaseIterable {
var displayName: String { get }
}
// A generic Picker that choose value of type PickerEnum
struct MyPicker<S: PickerEnum, Label: View>: View {
var selection: Binding<S>
let label: Label
var body: some View {
Picker(selection: selection, label: label) {
// Problem here: compile error
ForEach(S.allCases, id: \.self) { // Error: Generic struct 'ForEach' requires that 'S.AllCases' conform to 'RandomAccessCollection'
Text($0.displayName).tag($0)
}
}
.pickerStyle(SegmentedPickerStyle())
}
}
struct PickerDemo: View {
// Have many of these enum types choosable via SwiftUI.Picker
enum ColorMode: PickerEnum {
case light, dark, invisible
var displayName: String {
String(describing: self).capitalized
}
}
enum InputMode: PickerEnum {
case grid, spectrum, sliders
var displayName: String {
String(describing: self).capitalized
}
}
@State private var colorMode = ColorMode.light
@State private var inputMode = InputMode.grid
var body: some View {
VStack {
Text("Color: \(colorMode.displayName), Input type: \(inputMode.displayName)")
//
// Instead of have to write out Picker.init each time
//
Picker(selection: $colorMode, label: Text("Mode")) {
ForEach(ColorMode.allCases, id: \.self) { // <== ForEach(E.allCases is fine here!!
Text($0.displayName).tag($0)
}
}
.pickerStyle(SegmentedPickerStyle())
//
// Simply do this instead:
//
MyPicker(selection: $colorMode, label: Text("Mode"))
// Again, same
Picker(selection: $inputMode, label: Text("Input type")) {
ForEach(InputMode.allCases, id: \.self) {
Text($0.displayName).tag($0)
}
}
.pickerStyle(SegmentedPickerStyle())
MyPicker(selection: $inputMode, label: Text("Input type"))
}
}
}
struct PickerDemo_Previews: PreviewProvider {
static var previews: some View {
PickerDemo()
}
}