Create a list from enum - swiftui

I'd like to be able to create a List from an enum that conforms to CaseIterable and CustomStringConvertible e.g.
public enum HairColor: Int, Codable, CaseIterable, CustomStringConvertible {
public var description: String {
switch self {
case .black:
return "Black"
case .blond:
return "Blond"
case .brown:
return "Brown"
case .red:
return "Red"
case .grey:
return "Gray"
case .bald:
return "Bald"
}
}
case blond, brown, black, red, grey, bald
}
struct ContentView: View {
var body: some View {
SwiftUIHelpers.enumToList(HairColor)
}
}
This is the approach I've tried but I get the error: "Cannot convert value of type 'Text' to closure result type '_"
struct SwiftUIHelpers {
static func enumToList<T: CaseIterable, RandomAccessCollection>(_ a: T) -> some View {
List {
ForEach(a, id: \.rawValue) { (o: CustomStringConvertible) in
Text(o.description)
}
}
}
}
What is the error on my ways?!?

Here is working solution. Tested with Xcode 11.4 / iOS 13.4.
struct SwiftUIHelpers {
static func enumToList<T: CaseIterable>(_ t: T.Type) -> some View
where T.AllCases: RandomAccessCollection, T: Hashable & CustomStringConvertible {
List {
ForEach(t.self.allCases, id: \.self) { o in
Text(o.description)
}
}
}
}
struct ContentView: View {
var body: some View {
SwiftUIHelpers.enumToList(HairColor.self)
}
}
public enum HairColor: Int, Codable, Hashable, CaseIterable, CustomStringConvertible {
public var description: String {
switch self {
case .black:
return "Black"
case .blond:
return "Blond"
case .brown:
return "Brown"
case .red:
return "Red"
case .grey:
return "Gray"
case .bald:
return "Bald"
}
}
case blond, brown, black, red, grey, bald
}
Update: Having played with this more I've found that the following extension can be much more helpful
extension CaseIterable where Self.AllCases: RandomAccessCollection, Self: Hashable & CustomStringConvertible {
static func toForEach() -> some View {
ForEach(Self.allCases, id: \.self) { o in
Text(o.description).tag(o)
}
}
}
because gives wider reuse possibility, like
List { HairColor.toForEach() }
and this
Form { HairColor.toForEach() }
and
struct DemoHairColorPicker: View {
#State private var hairColor: HairColor = .red
var body: some View {
VStack {
Text("Selected: \(hairColor.description)")
Picker(selection: $hairColor, label: Text("Hair")) { HairColor.toForEach() }
}
}
}
and of course in any stack VStack { HairColor.toForEach() }

Not really an answer to all parts of your question - only the first part - but offered here as an alternative...
Might be worth considering the use of #EnvironmentObject for a #Published property? I used this to populate a sidebar style menu for a macOS target.
Step 1:
Use your enum. My enum is written a little differently to yours but I thought to leave it that way because it provides an alternate construction... but with the same outcome.
(Conforming to CaseIterable here allows us to use the .allCases method in Step 2.)
enum HairColor: Int, CaseIterable {
case blond = 0, brown, black, red, grey, none
var description: String {
switch self {
case .blond: return "Blond"
case .brown: return "Brown"
case .black: return "Black"
case .red: return "Red"
case .grey: return "Grey"
case .none: return "Bald"
}
}
}
Step 2:
Create a struct for your model and include a static property that maps all cases of your HairColor enum.
(Conforming to Identifiable here allows us to use the cleaner ForEach syntax in Step 4 - that is - use ForEach(appData.hairColors) in lieu of ForEach(appData.hairColors, id: \.id)).
import SwiftUI
struct Hair: Codable, Hashable, Identifiable {
var id: Int
var name: String
init(id: Int, name: String) {
self.id = id
self.name = name
}
static var colors: [Hair] {
return HairColor.allCases.map({ Hair(id: $0.rawValue, name: $0.description ) })
}
}
Step 3:
Create a class that conforms to ObservableObject and that contains a #Published wrapped property to allow you to broadcast your HairColor via #EnvironmentObject.
import Combine // <- don't forget this framework import!
import SwiftUI
final class AppData: ObservableObject {
#Published var hairColors = Hair.colors
}
Step 4:
Use in a View.
struct HairList: View {
#EnvironmentObject var appData: AppData
#State var selectedHair: Hair?
var body: some View {
VStack(alignment: .leading) {
Text("Select...")
.font(.headline)
List(selection: $selectedHair) {
ForEach(appData.hairColors) { hairColor in
Text(hairColor.name).tag(hairColor)
}
}
.listStyle(SidebarListStyle())
}
.frame(minWidth: 100, maxWidth: 150)
.padding()
}
}
Step 5:
Remember to inject the environment object into the preview to make the preview usable.
struct HairList_Previews: PreviewProvider {
static var previews: some View {
HairList(selectedHair: .constant(AppData().hairColors[1]))
.environmentObject(AppData())
}
}

Related

SwiftUI pass binding through NavigationStack enum

I am attempting to pass a Binding through my NavigationStack enum into my View. I'm not sure if I can pass Binding into an enum, if I cannot then how should I go about this. Thanks in advance!
#available(iOS 16.0, *)
enum Route: Hashable, Equatable {
//ERROR HERE: Not sure how to get Binding in enum or if possible
case gotoBView(input: Binding<String>)
#ViewBuilder
func view(_ path: Binding<NavigationPath>) -> some View{
switch self {
case .gotoBView(let input): BView1(bvar: input)
}
}
var isEmpty: Bool {
return false
}
}
//START VIEW
#available(iOS 16.0, *)
struct ContentView25: View {
#State var input = "Hello"
#State var path: NavigationPath = .init()
var body: some View {
NavigationStack(path: $path){
NavigationLink(value: Route.gotoBView(input: $input), label: {Text("Go To A")})
.navigationDestination(for: Route.self){ route in
route.view($path)
}
}
}
}
//View to navigate to with binding
#available(iOS 16.0, *)
struct BView1: View {
#Binding var bvar: String
var body: some View {
Text(bvar)
}
}
Here is a workaround, in previous iOS versions this has dismissed the NavigationLink, In iOS 16.2 it does not behave this way, I would do extensive testing before using this in a production app.
import SwiftUI
#available(iOS 16.0, *)
enum Route: Hashable, Equatable {
case gotoBView(input: Binding<String>)
#ViewBuilder
func view(_ path: Binding<NavigationPath>) -> some View{
switch self {
case .gotoBView(let input): BView1(bvar: input)
}
}
//Create a custom implementation of Hashable that ignores Binding
func hash(into hasher: inout Hasher) {
switch self {
case .gotoBView(let input):
hasher.combine(input.wrappedValue)
}
}
//Create a custom implementation of Equatable that ignores Binding
static func == (lhs: Route, rhs: Route) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
SwiftUI is all about identity and NavigationPath uses Hashable and Equatable to function. This bypasses SwiftUI's implementation.
With the stack, you don't need an enum, you can have multiple navigationDestination for each value type. To use it with a binding you can do it the old way, with a func that looks it up by ID, like how we did it before ForEach supported bindings, e.g.
struct NumberItem: Identifiable {
let id = UUID()
var number: Int
var text = ""
}
struct ContentView: View {
#State var numberItems = [NumberItem(number: 1), NumberItem(number: 2), NumberItem(number: 3), NumberItem(number: 4), NumberItem(number: 5)]
var body: some View {
NavigationStack {
List {
ForEach(numberItems) { numberItem in
NavigationLink(value: numberItem.id) {
Text("\(numberItem.number)")
}
}
}
.navigationDestination(for: NumberItem.ID.self) { numberItemID in
ChildDetailView(numberItems: $numberItems, numberItemID: numberItemID)
}
//.navigationDestination(for: AnotherItem.ID.self) { anotherItemID in
// ...
//}
}
}
}
// this wrapper View was originally needed to make bindings in
// navigationDestinations work at all, now its needed to fix a bug
// with the cursor jumping to the end of a text field which is
// using the binding.
struct ChildDetailView: View {
#Binding var numberItems: [NumberItem]
let numberItemID: UUID
var body: some View {
ChildDetailView2(numberItem: binding(for: numberItemID))
}
private func binding(for numberItemID: UUID) -> Binding<NumberItem> {
guard let index = numberItems.firstIndex(where: { $0.id == numberItemID }) else {
fatalError("Can't find item in array")
}
return $numberItems[index]
}
}
struct ChildDetailView2: View {
#Binding var numberItem: NumberItem
var body: some View {
VStack {
Text("\(numberItem.number)")
TextField("Test", text: $numberItem.text) // cursor jumps to the end if not wrapped in an extra View like this one is.
Button {
numberItem.number += 10
} label: {
Text("Add 10")
}
}
.navigationTitle("Detail")
}
}

SwiftUI 4: NavigationSplitView behaves strangely?

In SwiftUI 4, there is now a NavigationSplitView. I played around with it and detected some strange behaviour.
Consider the following code: When the content function returns the plain Text, then there is the expected behaviour - tapping a menu item changes the detail view to the related text.
However, when commenting out the first four cases, and commenting in the next four, then a tap on "Edit Profile" does not change the detail view display. (Using #ViewBuilder does not change this behaviour.)
Any ideas out there about the reasons for that? From my point of view, this may just be a simple bug, but perhaps there are things to be considered that are not documented yet?!
struct MainScreen: View {
#State private var menuItems = MenuItem.menuItems
#State private var menuItemSelection: MenuItem?
var body: some View {
NavigationSplitView {
List(menuItems, selection: $menuItemSelection) { course in
Text(course.name).tag(course)
}
.navigationTitle("HappyFreelancer")
} detail: {
content(menuItemSelection)
}
.navigationSplitViewStyle(.balanced)
}
func content(_ selection: MenuItem?) -> some View {
switch selection {
case .editProfile:
return Text("Edit Profile")
case .evaluateProfile:
return Text("Evaluate Profile")
case .setupApplication:
return Text("Setup Application")
case .none:
return Text("none")
// case .editProfile:
// return AnyView(EditProfileScreen())
//
// case .evaluateProfile:
// return AnyView(Text("Evaluate Profile"))
//
// case .setupApplication:
// return AnyView(Text("Setup Application"))
//
// case .none:
// return AnyView(Text("none"))
}
}
}
struct MainScreen_Previews: PreviewProvider {
static var previews: some View {
MainScreen()
}
}
enum MenuItem: Int, Identifiable, Hashable, CaseIterable {
var id: Int { rawValue }
case editProfile
case evaluateProfile
case setupApplication
var name: String {
switch self {
case .editProfile: return "Edit Profile"
case .evaluateProfile: return "Evaluate Profile"
case .setupApplication: return "Setup Application"
}
}
}
extension MenuItem {
static var menuItems: [MenuItem] {
MenuItem.allCases
}
}
struct EditProfileScreen: View {
var body: some View {
Text("Edit Profile")
}
}
After playing around a bit in order to force SwiftUI to redraw the details view, I succeeded in this workaround:
Wrap the NavigationSplitView into a GeometryReader.
Apply an .id(id) modifier to the GeometryReader (e.g., as #State private var id: Int = 0)
In this case, any menu item selection leads to a redraw as expected.
However, Apple should fix the bug, which it is obviously.
I've found that wrapping the Sidebar list within its own view will fix this issue:
struct MainView: View {
#State var selection: SidebarItem? = .none
var body: some View {
NavigationSplitView {
Sidebar(selection: $selection)
} content: {
content(for: selection)
} detail: {
Text("Detail")
}
}
#ViewBuilder
func content(for item: SidebarItem?) -> some View {
switch item {
case .none:
Text("Select an Item in the Sidebar")
case .a:
Text("A")
case .b:
Text("B")
}
}
}

Using switch/enums in SwiftUI Views

As of Xcode 11.4, SwiftUI doesn't allow switch statements in Function builder blocks like VStack {}, failing with a generic error like Generic parameter 'Content' could not be inferred. How can the switch statement be used in SwiftUI to create different Views depending on an enum value?
switch in SwiftUI view builders is supported since Xcode 12:
enum Status {
case loggedIn, loggedOut, expired
}
struct SwiftUISwitchView: View {
#State var userStatus: Status = .loggedIn
var body: some View {
VStack {
switch self.userStatus {
case .loggedIn:
Text("Welcome!")
case .loggedOut:
Image(systemName: "person.fill")
case .expired:
Text("Session expired")
}
}
}
}
You can use enum with #ViewBuilder as follow ...
Declear enum
enum Destination: CaseIterable, Identifiable {
case restaurants
case profile
var id: String { return title }
var title: String {
switch self {
case .restaurants: return "Restaurants"
case .profile: return "Profile"
}
}
}
Now in the View file
struct ContentView: View {
#State private var selectedDestination: Destination? = .restaurants
var body: some View {
NavigationView {
view(for: selectedDestination)
}
}
#ViewBuilder
func view(for destination: Destination?) -> some View {
switch destination {
case .some(.restaurants):
CategoriesView()
case .some(.profile):
ProfileView()
default:
EmptyView()
}
}
}
If you want to use the same case with the NavigationLink ... You can use it as follow
struct ContentView: View {
#State private var selectedDestination: Destination? = .restaurants
var body: some View {
NavigationView {
List(Destination.allCases,
selection: $selectedDestination) { item in
NavigationLink(destination: view(for: selectedDestination),
tag: item,
selection: $selectedDestination) {
Text(item.title).tag(item)
}
}
}
}
#ViewBuilder
func view(for destination: Destination?) -> some View {
switch destination {
case .some(.restaurants):
CategoriesView()
case .some(.profile):
ProfileView()
default:
EmptyView()
}
}
}

Picker for optional data type in SwiftUI?

Normally I can display a list of items like this in SwiftUI:
enum Fruit {
case apple
case orange
case banana
}
struct FruitView: View {
#State private var fruit = Fruit.apple
var body: some View {
Picker(selection: $fruit, label: Text("Fruit")) {
ForEach(Fruit.allCases) { fruit in
Text(fruit.rawValue).tag(fruit)
}
}
}
}
This works perfectly, allowing me to select whichever fruit I want. If I want to switch fruit to be nullable (aka an optional), though, it causes problems:
struct FruitView: View {
#State private var fruit: Fruit?
var body: some View {
Picker(selection: $fruit, label: Text("Fruit")) {
ForEach(Fruit.allCases) { fruit in
Text(fruit.rawValue).tag(fruit)
}
}
}
}
The selected fruit name is no longer displayed on the first screen, and no matter what selection item I choose, it doesn't update the fruit value.
How do I use Picker with an optional type?
The tag must match the exact data type as the binding is wrapping. In this case the data type provided to tag is Fruit but the data type of $fruit.wrappedValue is Fruit?. You can fix this by casting the datatype in the tag method:
struct FruitView: View {
#State private var fruit: Fruit?
var body: some View {
Picker(selection: $fruit, label: Text("Fruit")) {
ForEach(Fruit.allCases) { fruit in
Text(fruit.rawValue).tag(fruit as Fruit?)
}
}
}
}
Bonus: If you want custom text for nil (instead of just blank), and want the user to be allowed to select nil (Note: it's either all or nothing here), you can include an item for nil:
struct FruitView: View {
#State private var fruit: Fruit?
var body: some View {
Picker(selection: $fruit, label: Text("Fruit")) {
Text("No fruit").tag(nil as Fruit?)
ForEach(Fruit.allCases) { fruit in
Text(fruit.rawValue).tag(fruit as Fruit?)
}
}
}
}
Don't forget to cast the nil value as well.
I made a public repo here with Senseful's solution:
https://github.com/andrewthedina/SwiftUIPickerWithOptionalSelection
EDIT: Thank you for the comments regarding posting links. Here is the code which answers the question. Copy/paste will do the trick, or clone the repo from the link.
import SwiftUI
struct ContentView: View {
#State private var selectionOne: String? = nil
#State private var selectionTwo: String? = nil
let items = ["Item A", "Item B", "Item C"]
var body: some View {
NavigationView {
Form {
// MARK: - Option 1: NIL by SELECTION
Picker(selection: $selectionOne, label: Text("Picker with option to select nil item [none]")) {
Text("[none]").tag(nil as String?)
.foregroundColor(.red)
ForEach(items, id: \.self) { item in
Text(item).tag(item as String?)
// Tags must be cast to same type as Picker selection
}
}
// MARK: - Option 2: NIL by BUTTON ACTION
Picker(selection: $selectionTwo, label: Text("Picker with Button that removes selection")) {
ForEach(items, id: \.self) { item in
Text(item).tag(item as String?)
// Tags must be cast to same type as Picker selection
}
}
if selectionTwo != nil { // "Remove item" button only appears if selection is not nil
Button("Remove item") {
self.selectionTwo = nil
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I actually prefer #Senseful's solution for a point solution, but for posterity: you could also create a wrapper enum, which if you have a ton of entity types in your app scales quite nicely via protocol extensions.
// utility constraint to ensure a default id can be produced
protocol EmptyInitializable {
init()
}
// primary constraint on PickerValue wrapper
protocol Pickable {
associatedtype Element: Identifiable where Element.ID: EmptyInitializable
}
// wrapper to hide optionality
enum PickerValue<Element>: Pickable where Element: Identifiable, Element.ID: EmptyInitializable {
case none
case some(Element)
}
// hashable & equtable on the wrapper
extension PickerValue: Hashable & Equatable {
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
static func ==(lhs: Self, rhs: Self) -> Bool {
lhs.id == rhs.id
}
}
// common identifiable types
extension String: EmptyInitializable {}
extension Int: EmptyInitializable {}
extension UInt: EmptyInitializable {}
extension UInt8: EmptyInitializable {}
extension UInt16: EmptyInitializable {}
extension UInt32: EmptyInitializable {}
extension UInt64: EmptyInitializable {}
extension UUID: EmptyInitializable {}
// id producer on wrapper
extension PickerValue: Identifiable {
var id: Element.ID {
switch self {
case .some(let e):
return e.id
case .none:
return Element.ID()
}
}
}
// utility extensions on Array to wrap into PickerValues
extension Array where Element: Identifiable, Element.ID: EmptyInitializable {
var pickable: Array<PickerValue<Element>> {
map { .some($0) }
}
var optionalPickable: Array<PickerValue<Element>> {
[.none] + pickable
}
}
// benefit of wrapping with protocols is that item views can be common
// across data sets. (Here TitleComponent { var title: String { get }})
extension PickerValue where Element: TitleComponent {
#ViewBuilder
var itemView: some View {
Group {
switch self {
case .some(let e):
Text(e.title)
case .none:
Text("None")
.italic()
.foregroundColor(.accentColor)
}
}
.tag(self)
}
}
Usage is then quite tight:
Picker(selection: $task.job, label: Text("Job")) {
ForEach(Model.shared.jobs.optionalPickable) { p in
p.itemView
}
}
I learned almost all I know about SwiftUI Bindings (with Core Data) by reading this blog by Jim Dovey. The remainder is a combination of some research and quite a few hours of making mistakes.
So when I use Jim's technique to create Extensions on SwiftUI Binding then we end up with something like this...
public extension Binding where Value: Equatable {
init(_ source: Binding<Value>, deselectTo value: Value) {
self.init(get: { source.wrappedValue },
set: { source.wrappedValue = $0 == source.wrappedValue ? value : $0 }
)
}
}
Which can then be used throughout your code like this...
Picker("country", selection: Binding($selection, deselectTo: nil)) { ... }
OR
Picker("country", selection: Binding($selection, deselectTo: someOtherValue)) { ... }
OR when using .pickerStyle(.segmented)
Picker("country", selection: Binding($selection, deselectTo: -1)) { ... }
which sets the index of the segmented style picker to -1 as per the documentation for UISegmentedControl and selectedSegmentIndex.
The default value is noSegment (no segment selected) until the user
touches a segment. Set this property to -1 to turn off the current
selection.
Why not extending the enum with a default value? If this is not what you are trying to achieve, maybe you can also provide some information, why you want to have it optional.
enum Fruit: String, CaseIterable, Hashable {
case apple = "apple"
case orange = "orange"
case banana = "banana"
case noValue = ""
}
struct ContentView: View {
#State private var fruit = Fruit.noValue
var body: some View {
VStack{
Picker(selection: $fruit, label: Text("Fruit")) {
ForEach(Fruit.allCases, id:\.self) { fruit in
Text(fruit.rawValue)
}
}
Text("Selected Fruit: \(fruit.rawValue)")
}
}
}

Used SwiftUI picker and my MacBook heats up to 50 degrees

As soon as I use a code, my MacBook heats up to 50 degrees. I have 4 Enums that each have a picker, as soon as I put 3 pickers into an if-else statement and then debug, my MacBook heats up so much that I almost do it can not touch anymore.
error ->
The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
i use the enums with the protocols Int16, Hashable, CaseIterable.
i want Int16 for my CoreData Attribut.
If i change Int16 to Int then the Code Works..
i Convert in the "Taggs" to int so i can use the else if statemant.
Import SwiftUI
struct EnumsInEnums: View {
#State var pickMain = 0
#State var pickA = 0
#State var pickB = 0
#State var pickC = 0
enum MainEnum : Int16, Hashable, CaseIterable
{
case AEnum
case BEnum
case CEnum
var name: String { return "\(self)" }
}
enum AEnum : Int16, Hashable, CaseIterable
{
case Aa
case Ba
case Ca
var name: String { return "\(self)" }
}
enum BEnum : Int16, Hashable, CaseIterable
{
case Ab
case Bb
case Cb
var name: String { return "\(self)" }
}
enum CEnum : Int16, Hashable, CaseIterable
{
case Ac
case Bc
case Cc
var name: String { return "\(self)" }
}
var body: some View {
NavigationView {
Form {
Section {
Picker(selection: $pickMain, label: Text("Pick \(pickMain)")) {
ForEach(MainEnum.allCases, id: \.self){ x in
Text("\(x.name)").tag(Int(x.rawValue))
}
}
if pickMain == 0 {
Picker(selection: $pickA, label: Text("Pick \(pickA)")) {
ForEach(AEnum.allCases, id: \.self){ x in
Text("\(x.name)").tag(Int(x.rawValue))
}
}
} else if pickMain == 1 {
Picker(selection: $pickB, label: Text("Pick \(pickB)")) {
ForEach(BEnum.allCases, id: \.self){ x in
Text("\(x.name)").tag(Int(x.rawValue))
}
}
} else if pickMain == 2 {
Picker(selection: $pickC, label: Text("Pick \(pickC)")) {
ForEach(CEnum.allCases, id: \.self){ x in
Text("\(x.name)").tag(Int(x.rawValue))
}
}
}
}
}
}
}
}
I expect to select the Main and then the second picker will show me the selected, as if I would select an automaker and in the second picker come the respective car model.
In beta 5, there is a known problem with ForEach. From the release notes:
Using a ForEach view with a complex expression in its closure can may
result in compiler errors. Workaround: Extract those expressions into
their own View types. (53325810)
Your ForEach views, do not seem too complex, and encapsulating its contents does not solve the problem. However, if you encapsulate the entire pickers works fine. Double check the code, as I may have introduced a typo while encapsulating.
import SwiftUI
struct ContentView: View {
var body: some View {
EnumsInEnums()
}
}
struct EnumsInEnums: View {
#State var pickMain = 0
#State var pickA = 0
#State var pickB = 0
#State var pickC = 0
enum MainEnum : Int16, Hashable, CaseIterable
{
case AEnum
case BEnum
case CEnum
var name: String { return "\(self)" }
}
enum AEnum : Int16, Hashable, CaseIterable
{
case Aa
case Ba
case Ca
var name: String { return "\(self)" }
}
enum BEnum : Int16, Hashable, CaseIterable
{
case Ab
case Bb
case Cb
var name: String { return "\(self)" }
}
enum CEnum : Int16, Hashable, CaseIterable
{
case Ac
case Bc
case Cc
var name: String { return "\(self)" }
}
var body: some View {
NavigationView {
Form {
Section {
PickerMain(pickMain: $pickMain)
if pickMain == 0 {
PickerA(pickA: $pickA)
}
else if pickMain == 1 {
PickerB(pickB: $pickB)
} else if pickMain == 2 {
PickerC(pickC: $pickC)
}
}
}
}
}
struct PickerMain: View {
#Binding var pickMain: Int
var body: some View {
Picker(selection: $pickMain, label: Text("Pick \(pickMain)")) {
ForEach(MainEnum.allCases, id: \.self){ x in
Text("\(x.name)").tag(Int(x.rawValue))
}
}
}
}
struct PickerA: View {
#Binding var pickA: Int
var body: some View {
Picker(selection: $pickA, label: Text("Pick \(pickA)")) {
ForEach(AEnum.allCases, id: \.self){ x in
Text("\(x.name)").tag(Int(x.rawValue))
}
}
}
}
struct PickerB: View {
#Binding var pickB: Int
var body: some View {
Picker(selection: $pickB, label: Text("Pick \(pickB)")) {
ForEach(BEnum.allCases, id: \.self){ x in
Text("\(x.name)").tag(Int(x.rawValue))
}
}
}
}
struct PickerC: View {
#Binding var pickC: Int
var body: some View {
Picker(selection: $pickC, label: Text("Pick \(pickC)")) {
ForEach(CEnum.allCases, id: \.self){ x in
Text("\(x.name)").tag(Int(x.rawValue))
}
}
}
}
}