SwiftUI中DatePicker学习

文章介绍了如何在SwiftUI中使用DatePicker进行日期和时间选择,包括设置显示样式为滚动轮盘或日历列表,调整语言为中文,设置日期范围,以及处理日期排除等复杂需求。同时,提供了代码示例展示如何实现这些功能。
摘要由CSDN通过智能技术生成

在界面开发中,经常要使用到DatePicker控件,如年月日,时分选择。

但我们还要修改它的显示方式,文字语言,及其他功能

先看下最简单的调用方法就是:

@State private var date = Date()

var body: some View {
    DatePicker(
        "Start Date",
        selection: $date,
        displayedComponents: [.date]
    )
}

就是一个最简单的年月日选择控件,如图:

年月日时分显示时,不出现年份的解决方法

我们当然需要默认设置为当 年月日,时分都放在一起,想让用户一次性选择年月日,时,分,结果不行。

DatePicker( selection: $selectedDate, in: dateRange(), displayedComponents: [.date,.hourAndMinute]),啊!!!燚

因此需要分开两个DataPicker处理,如下

contentView: View {
        @State private var selectedDate = Date()  

        var body: some View {
            VStack {
                Text("Selected date: \(selectedDate, formatter: dateFormatter)")
                
                DatePicker( selection: $selectedDate, displayedComponents: [.date]){ 
                        Text("日期")
                    }
                         
                DatePicker(selection: $selectedDate, displayedComponents:  [.hourAndMinute]) {
                        Text("时间")
                    }
                   
            }
        }

显示效果如下:

滚动式控件的界面

就在DatePicker后面加上:.datePickerStyle(WheelDatePickerStyle()) 就可以。

显示效果如下:

DatePicker的中文化和国际化

那还有问题就是这个月份是英文的,我们需要修改为中文语言,就需要在DatePicker后面加上:.environment(.locale, Locale(identifier: "zh_CN"))。

当然如果是想国际化APP的话,就使用:.environment(\.locale, Locale.autoupdatingCurrent)

日历列表控件界面

还有一种显示效果是直接出现日期列表控件(不包括时分),如下

只需要把.datePickerStyle(WheelDatePickerStyle())修改.datePickerStyle(.graphical)就可以

以下是完整代码:

struct testView: View {
        @State private var selectedDate = Date()
         
        var body: some View {
            VStack {
                Text("Selected date: \(selectedDate, formatter: dateFormatter)")
                
                
                DatePicker( selection: $selectedDate, displayedComponents: [.date]){ //添加一个DatePicker视图,将它和selectedDate属性进行绑定,并设置DatePicker的组件类型为小时和分钟
                    Text("日期")
                }
                .datePickerStyle(WheelDatePickerStyle())
                
                .environment(\.locale, Locale.autoupdatingCurrent)
                //.environment(.locale, Locale(identifier: "zh_CN")) //中文显示
                
                
                DatePicker(selection: $selectedDate, displayedComponents:  [.hourAndMinute]) { //添加一个DatePicker视图,将它和selectedDate属性进行绑定,并设置DatePicker的组件类型为小时和分钟
                    Text("时间")
                }
                .datePickerStyle(WheelDatePickerStyle())
                
            }
        }

        private var dateFormatter: DateFormatter {
            let formatter = DateFormatter()
            formatter.dateStyle = .medium
            formatter.timeStyle = .long
            return formatter
        }
    }

日期设置范围

我们显示的日历列表,如果需要设置一个特定的日期范围,就可以,需要创建一个:ClosedRange<Date>,其实就是一个startDate...endDate,你可以先定义开始和结束日期:

let startDate = Calendar.current.date(from: DateComponents(year: 2023, month: 3, day: 1))! 

let endDate = Calendar.current.date(from: DateComponents(year: 2023, month: 6, day: 30))!

然后调用

DatePicker( "",selection: $selectedDate,in: startDate...endDate,displayedComponents: [.date]),也可以定义一个ClosedRange<Date>

func dateRange() -> ClosedRange<Date> {

            let startDate = dateFormatter.date(from: "20230301")!

            let endDate = dateFormatter.date(from: "20230630")!

            return startDate...endDate

        }

再调用:

DatePicker( "",selection: $selectedDate,in: dateRange(),displayedComponents: [.date])

日期格式设置

我们代码中有一个DateFormatter,他就是格式化输出日期表达式,并用来显示的,你可以根据你们需要来定义

private var dateFormatter1: DateFormatter {

        let formatter = DateFormatter()

        formatter.dateFormat = "yyyyMMdd"

            return formatter

    }

private var dateFormatter2: DateFormatter {

            let formatter = DateFormatter()

            formatter.dateStyle = .medium

            formatter.timeStyle = .long

            return formatter

        }

 例1

let startDate = dateFormatter1.date(from: "20230301")!  --这就比刚才那个

let startDate = Calendar.current.date(from: DateComponents(year: 2023, month: 3, day: 1))! 简单多了

例2

Text("Selected date: \(selectedDate, formatter: dateFormatter)")

显示为

日期排除

DatePicker设置一个日期范围(如20230301-20230630),但要排除其中20230302,20230303两天。目前DatePicker不支持排除,需要自己处理,我这有个不完美的方案,就是这个日期显示时,弹出提示,而没有实现为灰不能选择(下一步实现)

struct testView: View {
    @State private var selectedDate = Date()
    @State private var showInvalidDate = false
    @State private var invalidDate: Date?

    // 定义日期范围
    let dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyyMMdd"
        return formatter
    }()

    var body: some View {
        VStack {
            DatePicker("选择日期", selection: $selectedDate, in: dateRange(), displayedComponents: .date)
                .padding()
                .onReceive([self.selectedDate].publisher.first()) { date in
                    if disabledDates().contains(where: { Calendar.current.isDate($0, inSameDayAs: date) }) {
                        self.invalidDate = date
                        self.showInvalidDate = true
                        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
                            self.showInvalidDate = false
                        }
                        DispatchQueue.main.async {
                            self.selectedDate = self.previousValidDate(for: date)
                        }
                    }
                }
                .datePickerStyle(GraphicalDatePickerStyle())

            Text("所选日期:\(dateFormatter.string(from: selectedDate))")
                .padding()
        }
        .alert(isPresented: $showInvalidDate) {
            Alert(title: Text("不能选择"), message: Text("\(dateFormatter.string(from: invalidDate ?? selectedDate)) 无效。请重新选择日期。"), dismissButton: .default(Text("确定")))
        }
    }

    func dateRange() -> ClosedRange<Date> {
        let startDate = dateFormatter.date(from: "20230301")!
        let endDate = dateFormatter.date(from: "20230630")!

        return startDate...endDate
    }

    func disabledDates() -> [Date] {
        let disabledDateStrings: [String] = ["20230302", "20230303"]
        let disabledDates = disabledDateStrings.compactMap { dateFormatter.date(from: $0) }
        return disabledDates
    }

    func previousValidDate(for date: Date) -> Date {
        var previousDate = date
        while disabledDates().contains(where: { Calendar.current.isDate($0, inSameDayAs: previousDate) }) {
            previousDate = Calendar.current.date(byAdding: .day, value: -1, to: previousDate)!
        }
        return previousDate
    }
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值