Picker is a control which is used for selecting from a set of mutually exclusive values. It combines UISegmentedControland UIPickerView in one. Picker adapts the style of the platform it’s being rendered.
Picker is created by providing a selection binding, label and content for the picker label. Selection parameter is a bound property which provides the value to display for current selection.
Let’s look at an example.
We will start with an enum to store picker values we want to show. This enum will be String type and we will make it CaseIterable so we can iterate over the values. We also want to conform to the identifiable for this enum so each value can be identified uniquely.
We will have two computed properties for this enum, one to provide identity and other to return string representation of the enum value.
enum DevTechieCourseCategories: String, CaseIterable, Identifiable {
case swiftUI, uiKit, ml, swift
var id: Self { self }
var name: String {
switch self {
case .swift: return "Swift"
case .ml: return "Machine Learning"
case .swiftUI: return "SwiftUI"
case .uiKit: return "UIKit"
}
}
}
Next, we will create a view to host Picker view. We also want to create a State variable so we can bind selectionparameter for Picker view.
struct DevTechiePickerExample: View { @State private var selectedCategory: DevTechieCourseCategories = .swiftUI var body: some View {
NavigationStack {
Picker("Course Categories", selection: $selectedCategory) {
}
.navigationTitle("DevTechie.com")
}
}
}
We can create picker to select among the values by providing a collection of views for the picker content. We will start with simple Text view.
Note that the selection property actually looks at the tag property in Picker content to observe and reflect the change.
Because our enum conforms to CaseIterable, Identifiable protocols, we can optimize our code by wrapping content into a ForEach loop.
struct DevTechiePickerExample: View {
@State private var selectedCategory: DevTechieCourseCategories = .swiftUI
var body: some View {
NavigationStack {
Picker("Course Categories", selection: $selectedCategory) {
ForEach(DevTechieCourseCategories.allCases) { category in
Text(category.name)
.tag(category)
}
}
.navigationTitle("DevTechie.com")
}
}
}
Our app should work same as before.
Note: By default on iOS(starting iOS 15) default picker style is menu style. Also starting iOS 16, we get up down chevron for the label.
Starting iOS 16, Picker in List appears as menu style as well.
struct DevTechiePickerExample: View {
@State private var selectedCategory: DevTechieCourseCategories = .swiftUI
var body: some View {
NavigationStack {
List {
Picker("Course Categories", selection: $selectedCategory) {
ForEach(DevTechieCourseCategories.allCases) { category in
Text(category.name)
.tag(category)
}
}
}
.navigationTitle("DevTechie.com")
}
}
}
tag function doesn’t have to be bound to the type being selected, its there to keep the current selection but if you want to create a view where based upon Picker selection, you want to show some other value, we can do that. Let’s build an example.
Let’s update our code to suggest DevTechie’s video course based on selected category.
We will start by creating another enum to show a few DevTechie video courses(only a few there are more at DevTechie.com 😃).
enum DevTechieCourse: String, CaseIterable, Identifiable {
case materingSwiftUI4, machineLearningIniOS, learnSwiftByExample, buildStravaCloneInUiKit
var id: Self { self }
var name: String {
switch self {
case .materingSwiftUI4: return "Mastering SwiftUI 4"
case .machineLearningIniOS: return "Machine Learning in iOS"
case .buildStravaCloneInUiKit: return "Build Strava Clone in UIKit"
case .learnSwiftByExample: return "Learn Swift By Example"
}
}
}
We will add an extension to course category enum and create another computed property to return suggested video course based on selected category.
extension DevTechieCourseCategories {
var suggestedCourse: DevTechieCourse {
switch self {
case .swiftUI: return .materingSwiftUI4
case .ml: return .machineLearningIniOS
case .swift: return .learnSwiftByExample
case .uiKit: return .buildStravaCloneInUiKit
}
}
}
Next, we will replace State variable with a new one to keep suggestedCourse:
@State private var suggestedCourse = DevTechieCourse.materingSwiftUI4
We will change our picker to bind selected to this newly created State vaiable.
enum DevTechieCourseCategories: String, CaseIterable, Identifiable {
case swiftUI, uiKit, ml, swift
var id: Self { self }
var name: String {
switch self {
case .swift: return "Swift"
case .ml: return "Machine Learning"
case .swiftUI: return "SwiftUI"
case .uiKit: return "UIKit"
}
}
}enum DevTechieCourse: String, CaseIterable, Identifiable {
case materingSwiftUI4, machineLearningIniOS, learnSwiftByExample, buildStravaCloneInUiKit
var id: Self { self }
var name: String {
switch self {
case .materingSwiftUI4: return "Mastering SwiftUI 4"
case .machineLearningIniOS: return "Machine Learning in iOS"
case .buildStravaCloneInUiKit: return "Build Strava Clone in UIKit"
case .learnSwiftByExample: return "Learn Swift By Example"
}
}
}extension DevTechieCourseCategories {
var suggestedCourse: DevTechieCourse {
switch self {
case .swiftUI: return .materingSwiftUI4
case .ml: return .machineLearningIniOS
case .swift: return .learnSwiftByExample
case .uiKit: return .buildStravaCloneInUiKit
}
}
}struct DevTechiePickerExample: View {
@State private var suggestedCourse = DevTechieCourse.materingSwiftUI4
var body: some View {
NavigationStack {
List {
Picker("Course Categories", selection: $suggestedCourse) {
ForEach(DevTechieCourseCategories.allCases) { category in
Text(category.name)
.tag(category.suggestedCourse)
}
}
Section {
Text(suggestedCourse.name)
.foregroundColor(.secondary)
} header: {
Text("Suggested Course")
}}
.navigationTitle("DevTechie.com")
}
}
}
Build and run:
This example shows that Picker is bound to DevTechieCourse type while the options are all DevTechieCourseCategory instances. Each option uses the tag modifier to associate the suggested course with the category it displays.
Styling Pickers
We can change Picker style with pickerStyle modifier.
struct DevTechiePickerExample: View {
@State private var suggestedCourse = DevTechieCourse.materingSwiftUI4
var body: some View {
NavigationStack {
List {
Picker("Course Categories", selection: $suggestedCourse) {
ForEach(DevTechieCourseCategories.allCases) { category in
Text(category.name)
.tag(category.suggestedCourse)
}
}
.pickerStyle(.segmented)
Section {
Text(suggestedCourse.name)
.foregroundColor(.secondary)
} header: {
Text("Suggested Course")
}}
.navigationTitle("DevTechie.com")
}
}
}
.pickerStyle(.wheel)
.pickerStyle(.inline)
.pickerStyle(.inline)
We can create sections in Picker view. Let’s start by adding new course categories.
enum DevTechieCourseCategories: String, CaseIterable, Identifiable {
case swiftUI, uiKit, ml, swift
case flutter, kotlin
var id: Self { self }
var name: String {
switch self {
case .swift: return "Swift"
case .ml: return "Machine Learning"
case .swiftUI: return "SwiftUI"
case .uiKit: return "UIKit"
case .flutter: return "Flutter"
case .kotlin: return "Kotlin"
}
}
}
To match, we will update DevTechieCourse enum along with category extension:
enum DevTechieCourse: String, CaseIterable, Identifiable {
case materingSwiftUI4, machineLearningIniOS, learnSwiftByExample, buildStravaCloneInUiKit
case flutterDevForiOS, androidWithKotlin
var id: Self { self }
var name: String {
switch self {
case .materingSwiftUI4: return "Mastering SwiftUI 4"
case .machineLearningIniOS: return "Machine Learning in iOS"
case .buildStravaCloneInUiKit: return "Build Strava Clone in UIKit"
case .learnSwiftByExample: return "Learn Swift By Example"case .flutterDevForiOS: return "Flutter Dev for iOS"
case .androidWithKotlin: return "Learn Android with Kotlin"
}
}
}extension DevTechieCourseCategories {
var suggestedCourse: DevTechieCourse {
switch self {
case .swiftUI: return .materingSwiftUI4
case .ml: return .machineLearningIniOS
case .swift: return .learnSwiftByExample
case .uiKit: return .buildStravaCloneInUiKit
case .flutter: return .flutterDevForiOS
case .kotlin: return .androidWithKotlin
}
}
}
Let’s refactor our view to create two category collections so we can add sections to the Picker view.
var category1 = [DevTechieCourseCategories.swiftUI, .swift, .ml, .uiKit]
var category2 = [DevTechieCourseCategories.flutter, .kotlin]
Note: Picker selection seems to keep image around even for the entries where there is no image (Flutterand Kotlin are the example here). It could be a bug or feature 😉
With that we have reached the end of this article. Thank you once again for reading. Don’t forget to follow 😍. Also subscribe our newsletter at https://www.devtechie.com