Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A simple picker to pick a enum.
import SwiftUI
struct EnumPicker<T: Hashable & CaseIterable, V: View>: View {
@Binding var selected: T
var title: String? = nil
let mapping: (T) -> V
var body: some View {
Picker(selection: $selected, label: Text(title ?? "")) {
ForEach(Array(T.allCases), id: \.self) {
mapping($0).tag($0)
}
}
}
}
extension EnumPicker where T: RawRepresentable, T.RawValue == String, V == Text {
init(selected: Binding<T>, title: String? = nil) {
self.init(selected: selected, title: title) {
Text($0.rawValue)
}
}
}
@magnuskahr

This comment has been minimized.

Copy link
Owner Author

@magnuskahr magnuskahr commented Jul 16, 2020

It is really simple to use if you have a case iterable enum with a raw value of String:

enum PickerAction: String, CaseIterable {
  case source, targets
}

Just simply:

struct ContentView: View {
    @State private var pickerAction = PickerAction.source
    var body: some View {
      EnumPicker(selected: $pickerAction)
    }
}

As it will produce a Text-view itself; but if your enum does not have such string as a raw value, you can return a view in a closure:

EnumPicker(selected: $pickerAction) { e in
  // return view here
}

and you can of course also change the picker style, just add it to the environment: (Thanks @tobiasdm)

var body: some View {
  EnumPicker(selected: $pickerAction)
    .pickerStyle(SegmentedPickerStyle())
}

PS: If you rely on a custom view instead of the string value, remember that SegmentedPickerStyle can only show one Image or one Text-view per segment.

@imthath-m

This comment has been minimized.

Copy link

@imthath-m imthath-m commented Jul 17, 2020

It works great.

But in most cases, the raw values of the enums are not good enough to be displayed to the user and in some cases, we have Int as raw values. So I wrote another extension.

extension EnumPicker where T: Displayable, V == Text {
    init(selected: Binding<T>, title: String? = nil) {
        self.init(selected: selected, title: title) {
            Text($0.displayValue)
        }
    }
}

protocol Displayable {
    var displayValue: String { get }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment