You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI自定义时间选择器如何将Picker显示行数从10行改为3行

解决方案

SwiftUI 原生的滚轮样式Picker没有公开的行数调整参数,你可以通过固定选项行高+限制Picker总高度裁剪的方式实现仅显示3行的效果,修改逻辑如下:

  1. 给Picker内的每个文本选项设置固定行高,你可以根据你使用的字体大小调整数值,这里以行高60为例
  2. 给Picker设置3倍行高的固定高度,配合clipped()裁剪掉上下多余的内容,就能仅展示中间3行

修改后的TimePickerView核心代码

import SwiftUI

struct TimePickerView: View {
    @ObservedObject var timeViewModel = TimePickerViewModel()
    var numberPressed: ((Date) -> Void)?
    // 可根据设计调整行高
    private let pickerRowHeight: CGFloat = 60
    
    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)
                                    // 固定单行行高
                                    .frame(height: pickerRowHeight)
                                    .padding()
                                    .onTapGesture {
                                        timeViewModel.changeToMinutes = false
                                    }
                            }
                        }
                    }
                    .pickerStyle(.wheel)
                    .frame(maxWidth: geo.size.width * 0.4)
                    // 总高度为3行高度
                    .frame(height: pickerRowHeight * 3)
                    .clipped()
                    .compositingGroup()
                    // 可选:加渐变遮罩模拟原生Picker的上下半透明效果
                    .overlay {
                        LinearGradient(
                            colors: [.white.opacity(0.9), .clear, .white.opacity(0.9)],
                            startPoint: .top,
                            endPoint: .bottom
                        )
                        .allowsHitTesting(false)
                    }
                    
                    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)
                                    .frame(height: pickerRowHeight)
                                    .padding()
                                    .onTapGesture {
                                        timeViewModel.changeToMinutes = true
                                    }
                            }
                        }
                    }
                    .pickerStyle(.wheel)
                    .frame(maxWidth: geo.size.width * 0.4)
                    .frame(height: pickerRowHeight * 3)
                    .clipped()
                    .compositingGroup()
                    .overlay {
                        LinearGradient(
                            colors: [.white.opacity(0.9), .clear, .white.opacity(0.9)],
                            startPoint: .top,
                            endPoint: .bottom
                        )
                        .allowsHitTesting(false)
                    }
                    
                    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)")
                }
            }
            
        }
    }
}

修改后调整pickerRowHeight的数值即可匹配你需要的行高和总显示高度,实现3行显示的效果。


内容的提问来源于stack exchange,提问作者DanielRM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 03:45:03