Home > Software design >  SwiftUI - Reduce number of rows shown in a SwiftUI Picker
SwiftUI - Reduce number of rows shown in a SwiftUI Picker

Time:10-13

Currently the Picker in SwiftUI shows 10 rows of text by default. I would like to have it show only 3.

Context: I am working on a custom DatePicker which uses two Pickers as timeslots for hours and minutes. This is the UI i am trying to achieve (3 rows max per picker).

This is what I currently have (ignore different font and colors, since i have stripped down code for simplicity)

I have attached my code below. Any help would be greatly appreciated, thanks in advance.

TimePickerView.swift

import SwiftUI

struct TimePickerView: View {
    @ObservedObject var timeViewModel = TimePickerViewModel()
    var numberPressed: ((Date) -> Void)?
    
    var body: some View {
        GeometryReader { geo in
            VStack(alignment: .center) {
                HStack {
                    Picker("", selection: $timeViewModel.hour) {
                        ForEach(timeViewModel.hoursArray, id: \.self) { index in
                            HStack {
                                Text("\(index < 10 ? "0" : "")\(index)")
                                    .foregroundColor(.green)
                                    .font(.largeTitle)
                                    .padding()
                                    .onTapGesture {
                                        timeViewModel.changeToMinutes = false
                                    }
                            }
                        }
                    }
                    .pickerStyle(.wheel)
                    .frame(maxWidth: geo.size.width * 0.4)
                    .clipped()
                    .compositingGroup()
                    
                    Text(":")
                        .font(.largeTitle)
                        .foregroundColor(.orange)
                    
                    Picker("", selection: $timeViewModel.minutes) {
                        ForEach(timeViewModel.minutesArray, id: \.self) { index in
                            HStack {
                                Text("\(index < 10 ? "0" : "")\(index)")
                                    .foregroundColor(.green)
                                    .font(.largeTitle)
                                    .padding()
                                    .onTapGesture {
                                        timeViewModel.changeToMinutes = true
                                    }
                            }
                        }
                    }
                    .pickerStyle(.wheel)
                    .frame(maxWidth: geo.size.width * 0.4)
                    .clipped()
                    .compositingGroup()
                    
                    VStack {
                        Text("AM")
                            .font(.title2)
                            .fontWeight(timeViewModel.symbol == "AM" ? .bold : .light)
                            .foregroundColor(.orange)
                            .onTapGesture {
                                timeViewModel.symbol = "AM"
                            }
                        Text("PM")
                            .font(.title2)
                            .fontWeight(timeViewModel.symbol == "PM" ? .bold : .light)
                            .foregroundColor(.orange)
                            .onTapGesture {
                                timeViewModel.symbol = "PM"
                            }
                    }
                }
                .onChange(of: timeViewModel.selectedDate) { newDate in
                    self.numberPressed?(newDate)
                }
                
                HStack {
                    Text("hour \(timeViewModel.hour)")
                    Text("minute \(timeViewModel.minutes)")
                    Text("\(timeViewModel.symbol)")
                }
            }
            
        }
    }
}

TimePickerViewModel.swift

import Foundation

class TimePickerViewModel: ObservableObject {
    @Published var selectedDate = Date()
    
    @Published var hour: Int = 5
    @Published var minutes: Int = 5
    
    @Published var changeToMinutes = false
    // AM or PM....
    @Published var symbol = "AM"
    
    private(set) var hoursArray: [Int] = []
    private(set) var minutesArray: [Int] = []
    
    var currentPage = 0
    var perPage = 20
    
    init() {
        populateHoursAndMinArray()
        convertCurrentDateToHourAndMinutes()
    }
    
    func convertCurrentDateToHourAndMinutes() {
        let date = Date()
        let calendar = Calendar.current
        hour = calendar.component(.hour, from: date)
        minutes = calendar.component(.minute, from: date)
        
        if hour > 11 {
            symbol = "PM"
            switch hour {
            case 13:
                hour = 1
            case 14:
                hour = 2
            case 15:
                hour = 3
            case 16:
                hour = 4
            case 17:
                hour = 5
            case 18:
                hour = 6
            case 19:
                hour = 7
            case 20:
                hour = 8
            case 21:
                hour = 9
            case 22:
                hour = 10
            case 23:
                hour = 11
            case 24:
                hour = 0
            default:
                break
            }
        }
    }
    
    func populateHoursAndMinArray() {
        for index in 1 ... 12 {
            hoursArray.append(index)
        }
        
        for index in 0 ... 59 {
            minutesArray.append(index)
        }
    }
}

CodePudding user response:

You can set a maxHeight to the Pickers so they would show less number of rows

.frame(maxWidth: geo.size.width * 0.4, maxHeight: 80)

enter image description here

  • Related