Picker / Segmented Control - SwiftUI

Jun 14, 2022 2 min read
Picker / Segmented Control - SwiftUI

Updated for iOS 15

Segmented control


SwiftUI’s Picker can also be used to create segmented controls equivalent to UISegmentedControl from UIKit, although it needs to be bound to some state and you must ensure to give each segment a tag so it can be identified. Segments can be text or pictures; anything else will silently fail. Example:

struct ContentView: View {
    @State private var favoriteColor = "Red"
    var colors = ["Red", "Green", "Blue"]

    var body: some View {
        VStack {
            Picker("What is your favorite color?", selection: $favoriteColor) {
                ForEach(colors, id: \.self) {
                    Text($0)
                }
            }
            .pickerStyle(.segmented)

            Text("Value: \(favoriteColor)")
        }
    }
}

Picker


Date picker

SwiftUI gives us a dedicated picker type called DatePicker that can be bound to a date property. Yes, Swift has a dedicated type for working with dates, and it’s called – unsurprisingly – Date.

Screenshot
Reveal Code

struct ContentView: View {
    
    @State private var wakeUp = Date()
    
    // when you create a new Date instance it will be set to the current date and time
    let now = Date()

    // create a second Date instance set to one day in seconds from now
    let tomorrow = Date().addingTimeInterval(86400)
    
    var body: some View {
        
        VStack{
            DatePicker("Please enter a time", selection: $wakeUp, displayedComponents: .hourAndMinute)
            
            DatePicker("Please enter a date", selection: $wakeUp, in: Date()...)
            .labelsHidden()
        }
        
    }
}

Multi-Component Picker

Screenshot
Reveal Code

import SwiftUI

struct ContentView: View {
    
    @State var data: [(String, [String])] = [
        ("One", Array(0...10).map { "\($0)" }),
        ("Two", Array(20...40).map { "\($0)" }),
        ("Three", Array(100...200).map { "\($0)" })
    ]
    @State var selection: [String] = [0, 20, 100].map { "\($0)" }
    
    var body: some View {
        VStack(alignment: .center) {
            Text(verbatim: "Selection: \(selection)")
            MultiPicker(data: data, selection: $selection).frame(height: 300)
        }
    }
    
}

struct MultiPicker: View  {
    
    typealias Label = String
    typealias Entry = String
    
    let data: [ (Label, [Entry]) ]
    @Binding var selection: [Entry]
    
    var body: some View {
        GeometryReader { geometry in
            HStack {
                ForEach(0..<self.data.count) { column in
                    Picker(self.data[column].0, selection: self.$selection[column]) {
                        ForEach(0..<self.data[column].1.count) { row in
                            Text(verbatim: self.data[column].1[row])
                                .tag(self.data[column].1[row])
                        }
                    }
                    .pickerStyle(WheelPickerStyle())
                    .frame(width: geometry.size.width / CGFloat(self.data.count), height: geometry.size.height)
                    .clipped()
                }
            }
        }
    }
}

Great! Next, complete checkout for full access to ArturoFM.
Welcome back! You've successfully signed in.
You've successfully subscribed to ArturoFM.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info has been updated.
Your billing was not updated.