Article / 2026/05/29

UIDatePicker 完整 API 指南

UIDatePicker 是 UIKit 框架中用于选择日期和时间的控件,它提供了多种显示样式和配置选项,可以满足不同的日期时间选择需求。

🚀 UIDatePicker 完整 API 指南

概述

UIDatePicker 是 UIKit 框架中用于选择日期和时间的控件,它提供了多种显示样式和配置选项,可以满足不同的日期时间选择需求。

基本初始化

创建 UIDatePicker

// 基本初始化
let datePicker = UIDatePicker()

// 带 frame 初始化
let datePicker = UIDatePicker(frame: CGRect(x: 0, y: 0, width: 320, height: 200))

核心属性 (Properties)

1. 日期相关属性

date: Date

当前选中的日期

let datePicker = UIDatePicker()

// 设置当前日期
datePicker.date = Date()

// 获取选中的日期
let selectedDate = datePicker.date

// 设置特定日期
let calendar = Calendar.current
let specificDate = calendar.date(from: DateComponents(year: 2024, month: 12, month: 25))!
datePicker.date = specificDate

minimumDate: Date?

可选择的最小日期

let datePicker = UIDatePicker()

// 设置最小日期为今天
datePicker.minimumDate = Date()

// 设置最小日期为去年
let calendar = Calendar.current
let lastYear = calendar.date(byAdding: .year, value: -1, to: Date())
datePicker.minimumDate = lastYear

// 清除最小日期限制
datePicker.minimumDate = nil

maximumDate: Date?

可选择的最大日期

let datePicker = UIDatePicker()

// 设置最大日期为明年
let calendar = Calendar.current
let nextYear = calendar.date(byAdding: .year, value: 1, to: Date())
datePicker.maximumDate = nextYear

// 设置最大日期为今天(不能选择未来日期)
datePicker.maximumDate = Date()

// 清除最大日期限制
datePicker.maximumDate = nil

2. 显示模式属性

datePickerMode: UIDatePicker.Mode

日期选择器的显示模式

let datePicker = UIDatePicker()

// 时间模式(小时和分钟)
datePicker.datePickerMode = .time

// 日期模式(年月日)
datePicker.datePickerMode = .date

// 日期和时间模式
datePicker.datePickerMode = .dateAndTime

// 倒计时模式
datePicker.datePickerMode = .countDownTimer

模式说明

  • .time: 显示小时和分钟选择器
  • .date: 显示年、月、日选择器
  • .dateAndTime: 同时显示日期和时间
  • .countDownTimer: 显示倒计时(小时和分钟)

preferredDatePickerStyle: UIDatePickerStyle (iOS 13.4+)

首选的日期选择器样式

let datePicker = UIDatePicker()

// 自动样式(系统决定)
datePicker.preferredDatePickerStyle = .automatic

// 滚轮样式
datePicker.preferredDatePickerStyle = .wheels

// 紧凑样式
datePicker.preferredDatePickerStyle = .compact

// 日历样式 (iOS 14.0+)
if #available(iOS 14.0, *) {
    datePicker.preferredDatePickerStyle = .graphical
}

样式说明

  • .automatic: 系统根据上下文自动选择
  • .wheels: 传统的滚轮样式
  • .compact: 紧凑的按钮样式,点击后弹出选择器
  • .graphical: 日历网格样式(仅限日期模式)

3. 本地化属性

locale: Locale?

用于格式化日期的区域设置

let datePicker = UIDatePicker()

// 设置为中文区域
datePicker.locale = Locale(identifier: "zh_CN")

// 设置为英文区域
datePicker.locale = Locale(identifier: "en_US")

// 设置为日文区域
datePicker.locale = Locale(identifier: "ja_JP")

// 使用系统默认区域
datePicker.locale = Locale.current

calendar: Calendar?

用于日期计算的日历

let datePicker = UIDatePicker()

// 设置为公历
datePicker.calendar = Calendar(identifier: .gregorian)

// 设置为农历
datePicker.calendar = Calendar(identifier: .chinese)

// 设置为伊斯兰历
datePicker.calendar = Calendar(identifier: .islamicCivil)

// 使用系统默认日历
datePicker.calendar = Calendar.current

timeZone: TimeZone?

用于显示日期的时区

let datePicker = UIDatePicker()

// 设置为东京时区
datePicker.timeZone = TimeZone(identifier: "Asia/Tokyo")

// 设置为纽约时区
datePicker.timeZone = TimeZone(identifier: "America/New_York")

// 设置为UTC时区
datePicker.timeZone = TimeZone(abbreviation: "UTC")

// 使用系统默认时区
datePicker.timeZone = TimeZone.current

4. 倒计时模式属性

countDownDuration: TimeInterval

倒计时模式下的持续时间(秒)

let datePicker = UIDatePicker()
datePicker.datePickerMode = .countDownTimer

// 设置5分钟倒计时
datePicker.countDownDuration = 5 * 60

// 设置1小时倒计时
datePicker.countDownDuration = 60 * 60

// 设置2小时30分钟倒计时
datePicker.countDownDuration = 2.5 * 60 * 60

// 获取当前倒计时时长
let duration = datePicker.countDownDuration
let minutes = Int(duration) / 60

minuteInterval: Int

分钟选择的间隔

let datePicker = UIDatePicker()

// 设置5分钟间隔(0, 5, 10, 15, 20, 25, 30...)
datePicker.minuteInterval = 5

// 设置15分钟间隔(0, 15, 30, 45)
datePicker.minuteInterval = 15

// 设置30分钟间隔(0, 30)
datePicker.minuteInterval = 30

// 默认1分钟间隔
datePicker.minuteInterval = 1

注意: minuteInterval 必须是 60 的约数(1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30)

核心方法 (Methods)

1. 设置日期方法

setDate(_:animated:)

设置选中的日期,可选择是否使用动画

let datePicker = UIDatePicker()

// 无动画设置日期
datePicker.setDate(Date(), animated: false)

// 有动画设置日期
datePicker.setDate(Date(), animated: true)

// 设置特定日期
let calendar = Calendar.current
let specificDate = calendar.date(from: DateComponents(year: 2025, month: 6, day: 15))!
datePicker.setDate(specificDate, animated: true)

事件处理

Target-Action 模式

UIControl.Event.valueChanged

日期选择器值改变时触发的事件

let datePicker = UIDatePicker()

// 添加值改变事件监听
datePicker.addTarget(self, action: #selector(dateChanged(_:)), for: .valueChanged)

@objc func dateChanged(_ sender: UIDatePicker) {
    let selectedDate = sender.date
    print("选中的日期: \(selectedDate)")
    
    // 格式化日期显示
    let formatter = DateFormatter()
    formatter.locale = Locale(identifier: "zh_CN")
    formatter.dateStyle = .full
    formatter.timeStyle = .short
    
    let formattedDate = formatter.string(from: selectedDate)
    print("格式化日期: \(formattedDate)")
}

在 SwiftUI 中使用 UIDatePicker

基本 UIViewRepresentable 包装

struct UIDatePickerWrapper: UIViewRepresentable {
    @Binding var selectedDate: Date
    var datePickerMode: UIDatePicker.Mode = .date
    var preferredStyle: UIDatePickerStyle = .wheels
    var minimumDate: Date? = nil
    var maximumDate: Date? = nil
    var minuteInterval: Int = 1
    var locale: Locale? = nil
    
    func makeUIView(context: Context) -> UIDatePicker {
        let datePicker = UIDatePicker()
        
        // 配置基本属性
        datePicker.datePickerMode = datePickerMode
        datePicker.preferredDatePickerStyle = preferredStyle
        datePicker.minimumDate = minimumDate
        datePicker.maximumDate = maximumDate
        datePicker.minuteInterval = minuteInterval
        datePicker.locale = locale
        
        // 添加事件监听
        datePicker.addTarget(
            context.coordinator,
            action: #selector(Coordinator.dateChanged(_:)),
            for: .valueChanged
        )
        
        return datePicker
    }
    
    func updateUIView(_ uiView: UIDatePicker, context: Context) {
        uiView.date = selectedDate
        uiView.datePickerMode = datePickerMode
        uiView.preferredDatePickerStyle = preferredStyle
        uiView.minimumDate = minimumDate
        uiView.maximumDate = maximumDate
        uiView.minuteInterval = minuteInterval
        uiView.locale = locale
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject {
        let parent: UIDatePickerWrapper
        
        init(_ parent: UIDatePickerWrapper) {
            self.parent = parent
        }
        
        @objc func dateChanged(_ sender: UIDatePicker) {
            parent.selectedDate = sender.date
        }
    }
}

使用示例

struct ContentView: View {
    @State private var selectedDate = Date()
    @State private var birthDate = Date()
    @State private var meetingTime = Date()
    
    var body: some View {
        VStack(spacing: 30) {
            // 日期选择器
            VStack {
                Text("选择日期")
                UIDatePickerWrapper(
                    selectedDate: $selectedDate,
                    datePickerMode: .date,
                    preferredStyle: .wheels,
                    locale: Locale(identifier: "zh_CN")
                )
                .frame(height: 200)
            }
            
            // 生日选择器(限制最大日期为今天)
            VStack {
                Text("选择生日")
                UIDatePickerWrapper(
                    selectedDate: $birthDate,
                    datePickerMode: .date,
                    preferredStyle: .graphical,
                    maximumDate: Date()
                )
                .frame(height: 300)
            }
            
            // 会议时间选择器(15分钟间隔)
            VStack {
                Text("选择会议时间")
                UIDatePickerWrapper(
                    selectedDate: $meetingTime,
                    datePickerMode: .time,
                    preferredStyle: .wheels,
                    minuteInterval: 15
                )
                .frame(height: 150)
            }
        }
        .padding()
    }
}

高级配置示例

1. 完全自定义的日期选择器

struct AdvancedDatePicker: UIViewRepresentable {
    @Binding var selectedDate: Date
    
    let configuration: Configuration
    
    struct Configuration {
        var mode: UIDatePicker.Mode = .date
        var style: UIDatePickerStyle = .wheels
        var minimumDate: Date? = nil
        var maximumDate: Date? = nil
        var minuteInterval: Int = 1
        var locale: Locale? = Locale.current
        var calendar: Calendar? = Calendar.current
        var timeZone: TimeZone? = TimeZone.current
        var backgroundColor: UIColor? = nil
        var tintColor: UIColor? = nil
    }
    
    func makeUIView(context: Context) -> UIDatePicker {
        let datePicker = UIDatePicker()
        
        // 应用配置
        datePicker.datePickerMode = configuration.mode
        datePicker.preferredDatePickerStyle = configuration.style
        datePicker.minimumDate = configuration.minimumDate
        datePicker.maximumDate = configuration.maximumDate
        datePicker.minuteInterval = configuration.minuteInterval
        datePicker.locale = configuration.locale
        datePicker.calendar = configuration.calendar
        datePicker.timeZone = configuration.timeZone
        
        if let backgroundColor = configuration.backgroundColor {
            datePicker.backgroundColor = backgroundColor
        }
        
        if let tintColor = configuration.tintColor {
            datePicker.tintColor = tintColor
        }
        
        datePicker.addTarget(
            context.coordinator,
            action: #selector(Coordinator.dateChanged(_:)),
            for: .valueChanged
        )
        
        return datePicker
    }
    
    func updateUIView(_ uiView: UIDatePicker, context: Context) {
        uiView.date = selectedDate
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject {
        let parent: AdvancedDatePicker
        
        init(_ parent: AdvancedDatePicker) {
            self.parent = parent
        }
        
        @objc func dateChanged(_ sender: UIDatePicker) {
            parent.selectedDate = sender.date
        }
    }
}

2. 使用示例

struct AdvancedDatePickerExample: View {
    @State private var selectedDate = Date()
    
    var body: some View {
        AdvancedDatePicker(
            selectedDate: $selectedDate,
            configuration: AdvancedDatePicker.Configuration(
                mode: .dateAndTime,
                style: .graphical,
                minimumDate: Calendar.current.date(byAdding: .day, value: -30, to: Date()),
                maximumDate: Calendar.current.date(byAdding: .day, value: 30, to: Date()),
                minuteInterval: 15,
                locale: Locale(identifier: "zh_CN"),
                backgroundColor: UIColor.systemBackground,
                tintColor: UIColor.systemBlue
            )
        )
        .frame(height: 400)
    }
}

常见使用场景

1. 生日选择器

struct BirthdayPicker: View {
    @State private var birthDate = Date()
    
    var body: some View {
        UIDatePickerWrapper(
            selectedDate: $birthDate,
            datePickerMode: .date,
            preferredStyle: .graphical,
            maximumDate: Date(), // 不能选择未来日期
            locale: Locale(identifier: "zh_CN")
        )
    }
}

2. 倒计时选择器

struct CountdownPicker: View {
    @State private var countdownDate = Date()
    
    var body: some View {
        UIDatePickerWrapper(
            selectedDate: $countdownDate,
            datePickerMode: .countDownTimer,
            preferredStyle: .wheels,
            minuteInterval: 5
        )
    }
}

3. 会议时间选择器

struct MeetingTimePicker: View {
    @State private var meetingTime = Date()
    
    private var workingHoursStart: Date {
        Calendar.current.date(bySettingHour: 9, minute: 0, second: 0, of: Date()) ?? Date()
    }
    
    private var workingHoursEnd: Date {
        Calendar.current.date(bySettingHour: 18, minute: 0, second: 0, of: Date()) ?? Date()
    }
    
    var body: some View {
        UIDatePickerWrapper(
            selectedDate: $meetingTime,
            datePickerMode: .time,
            preferredStyle: .wheels,
            minimumDate: workingHoursStart,
            maximumDate: workingHoursEnd,
            minuteInterval: 30
        )
    }
}

最佳实践

1. 性能优化

// 避免频繁更新,使用防抖动
class DatePickerViewModel: ObservableObject {
    @Published var selectedDate = Date()
    private var cancellables = Set<AnyCancellable>()
    
    init() {
        // 防抖动:延迟0.3秒后才处理日期变化
        $selectedDate
            .debounce(for: .milliseconds(300), scheduler: RunLoop.main)
            .sink { date in
                self.handleDateChange(date)
            }
            .store(in: &cancellables)
    }
    
    private func handleDateChange(_ date: Date) {
        // 处理日期变化
        print("最终选择的日期: \(date)")
    }
}

2. 错误处理

struct SafeDatePicker: UIViewRepresentable {
    @Binding var selectedDate: Date
    let dateRange: ClosedRange<Date>
    
    func makeUIView(context: Context) -> UIDatePicker {
        let datePicker = UIDatePicker()
        
        // 确保初始日期在有效范围内
        let clampedDate = clampDate(selectedDate, to: dateRange)
        datePicker.date = clampedDate
        datePicker.minimumDate = dateRange.lowerBound
        datePicker.maximumDate = dateRange.upperBound
        
        datePicker.addTarget(
            context.coordinator,
            action: #selector(Coordinator.dateChanged(_:)),
            for: .valueChanged
        )
        
        return datePicker
    }
    
    func updateUIView(_ uiView: UIDatePicker, context: Context) {
        let clampedDate = clampDate(selectedDate, to: dateRange)
        if uiView.date != clampedDate {
            uiView.setDate(clampedDate, animated: true)
        }
    }
    
    private func clampDate(_ date: Date, to range: ClosedRange<Date>) -> Date {
        return min(max(date, range.lowerBound), range.upperBound)
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject {
        let parent: SafeDatePicker
        
        init(_ parent: SafeDatePicker) {
            self.parent = parent
        }
        
        @objc func dateChanged(_ sender: UIDatePicker) {
            parent.selectedDate = sender.date
        }
    }
}

3. 国际化支持

struct LocalizedDatePicker: View {
    @State private var selectedDate = Date()
    
    var body: some View {
        UIDatePickerWrapper(
            selectedDate: $selectedDate,
            datePickerMode: .date,
            preferredStyle: .graphical,
            locale: Locale.current
        )
        .environment(\.locale, Locale.current)
    }
}

版本兼容性

  • iOS 2.0+: 基本 UIDatePicker 功能
  • iOS 13.4+: preferredDatePickerStyle 属性
  • iOS 14.0+: graphical 样式
  • iOS 15.0+: 改进的紧凑样式支持

常见问题解决

1. 样式不生效

// 确保在 iOS 13.4+ 中设置样式
if #available(iOS 13.4, *) {
    datePicker.preferredDatePickerStyle = .wheels
}

2. 日期格式问题

// 使用正确的 Locale 和 Calendar
datePicker.locale = Locale(identifier: "zh_CN")
datePicker.calendar = Calendar(identifier: .gregorian)

3. 约束问题

// 设置正确的约束优先级
datePicker.setContentHuggingPriority(.defaultLow, for: .horizontal)
datePicker.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)

UIDatePicker 是一个功能强大且灵活的日期时间选择控件,通过合理使用其 API 可以创建出优秀的用户体验。记住要根据具体的使用场景选择合适的模式和样式,并注意处理边界情况和国际化需求。

Giscus 未启用:请在 src/site.config.ts 中配置 repoId 与 categoryId。