Skip to content

Instantly share code, notes, and snippets.

@shaps80
Last active September 18, 2024 03:01
Show Gist options
  • Save shaps80/890f374f67be14c561896f19da4e2a55 to your computer and use it in GitHub Desktop.
Save shaps80/890f374f67be14c561896f19da4e2a55 to your computer and use it in GitHub Desktop.
import SwiftUI
public extension Picker where SelectionValue: CaseIterable, SelectionValue.AllCases: RandomAccessCollection, SelectionValue: RawRepresentable, SelectionValue.RawValue == String {
init(_ title: some StringProtocol, selection: Binding<SelectionValue>) where Label == Text, Content == ForEach<SelectionValue.AllCases, SelectionValue, Text> {
self.init(title, selection: selection) {
ForEach(SelectionValue.allCases, id: \.self) { element in
Text(element.rawValue)
}
}
}
init(_ titleKey: LocalizedStringKey, selection: Binding<SelectionValue>) where Label == Text, Content == ForEach<SelectionValue.AllCases, SelectionValue, Text> {
self.init(titleKey, selection: selection) {
ForEach(SelectionValue.allCases, id: \.self) { element in
Text(element.rawValue)
}
}
}
init(_ title: some StringProtocol, systemImage: String, selection: Binding<SelectionValue>) where Label == SwiftUI.Label<Text, Image>, Content == ForEach<SelectionValue.AllCases, SelectionValue, Text> {
self.init(title, systemImage: systemImage, selection: selection) {
ForEach(SelectionValue.allCases, id: \.self) { element in
Text(element.rawValue)
}
}
}
init(_ titleKey: LocalizedStringKey, systemImage: String, selection: Binding<SelectionValue>) where Label == SwiftUI.Label<Text, Image>, Content == ForEach<SelectionValue.AllCases, SelectionValue, Text> {
self.init(titleKey, systemImage: systemImage, selection: selection) {
ForEach(SelectionValue.allCases, id: \.self) { element in
Text(element.rawValue)
}
}
}
init(selection: Binding<SelectionValue>, @ViewBuilder label: () -> Label) where Content == ForEach<SelectionValue.AllCases, SelectionValue, Text> {
self.init(selection: selection, content: {
ForEach(SelectionValue.allCases, id: \.self) { element in
Text(element.rawValue)
}
}, label: label)
}
}
public extension Picker where SelectionValue: CaseIterable, SelectionValue.AllCases: RandomAccessCollection, SelectionValue.AllCases.Element: Hashable {
typealias Element = SelectionValue.AllCases.Element
init<C: View>(_ title: some StringProtocol, selection: Binding<SelectionValue>, @ViewBuilder content: @escaping (Element) -> C) where Label == Text, Content == ForEach<SelectionValue.AllCases, SelectionValue, C> {
self.init(title, selection: selection) {
ForEach(SelectionValue.allCases, id: \.self, content: content)
}
}
init<C: View>(_ titleKey: LocalizedStringKey, selection: Binding<SelectionValue>, @ViewBuilder content: @escaping (Element) -> C) where Label == Text, Content == ForEach<SelectionValue.AllCases, SelectionValue, C> {
self.init(titleKey, selection: selection) {
ForEach(SelectionValue.allCases, id: \.self, content: content)
}
}
init<C: View>(_ title: some StringProtocol, systemImage: String, selection: Binding<SelectionValue>, @ViewBuilder content: @escaping (Element) -> C) where Label == SwiftUI.Label<Text, Image>, Content == ForEach<SelectionValue.AllCases, SelectionValue, C> {
self.init(title, systemImage: systemImage, selection: selection) {
ForEach(SelectionValue.allCases, id: \.self, content: content)
}
}
init<C: View>(_ titleKey: LocalizedStringKey, systemImage: String, selection: Binding<SelectionValue>, @ViewBuilder content: @escaping (Element) -> C) where Label == SwiftUI.Label<Text, Image>, Content == ForEach<SelectionValue.AllCases, SelectionValue, C> {
self.init(titleKey, systemImage: systemImage, selection: selection) {
ForEach(SelectionValue.allCases, id: \.self, content: content)
}
}
init<C: View>(selection: Binding<SelectionValue>, @ViewBuilder content: @escaping (Element) -> C, @ViewBuilder label: () -> Label) where Content == ForEach<SelectionValue.AllCases, SelectionValue, C> {
self.init(selection: selection, content: {
ForEach(SelectionValue.allCases, id: \.self, content: content)
}, label: label)
}
}
public extension Picker where SelectionValue: CaseIterable, SelectionValue.AllCases: RandomAccessCollection, SelectionValue.AllCases.Element: Hashable {
init(_ title: some StringProtocol, selection: Binding<SelectionValue>, value: KeyPath<SelectionValue.AllCases.Element, String>) where Label == Text, Content == ForEach<SelectionValue.AllCases, SelectionValue, Text> {
self.init(title, selection: selection) {
ForEach(SelectionValue.allCases, id: \.self) {
Text($0[keyPath: value])
}
}
}
init(_ titleKey: LocalizedStringKey, selection: Binding<SelectionValue>, value: KeyPath<SelectionValue.AllCases.Element, String>) where Label == Text, Content == ForEach<SelectionValue.AllCases, SelectionValue, Text> {
self.init(titleKey, selection: selection) {
ForEach(SelectionValue.allCases, id: \.self) {
Text($0[keyPath: value])
}
}
}
}
@shaps80
Copy link
Author

shaps80 commented Sep 11, 2024

Example:

enum Test: String, CaseIterable {
    case foo
    case bar
}

extension Orientation {
    var name: String {
        switch self {
        case .portrait:
            return "Portrait"
        case .landscapeLeft:
            return "Landscape Left"
        case .landscapeRight:
            return "Landscape Right"
        }
    }
}

struct ContentView: View {
    @State private var test: Test = .foo
    @State private var orientation: Orientation = .portrait

    var body: some View {
        List {
            Picker("Test", selection: $test)
            Picker("Orientation", selection: $orientation, value: \.name)
        }
    }
}

@yujinqiu
Copy link

yujinqiu commented Sep 13, 2024

@shaps80 is it possible if Orientation name is LocalizedStringKey ?
It's does no support now, I've test it :-(

extension Orientation {
    var name: LocalizedStringKey {
        switch self {
        case .portrait:
            return "Portrait"
        case .landscapeLeft:
            return "Landscape Left"
        case .landscapeRight:
            return "Landscape Right"
        }
    }
}

@shaps80
Copy link
Author

shaps80 commented Sep 16, 2024

Should be, pretty sure I included those inits as they're extremely useful and generally expected in SwiftUI. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment