This article talks about the development of date picker ideas

The following figure shows the deadline picker


Develop a selector, just two points

1. Data source

Data sources are divided into, how many columns, how many columns, what content each one presents

  • How many bar
// 3 column func numberOfComponents(in pickerView: UIPickerView) -> Int {return 3}Copy the code
  • How many in a column
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { switch component { case 0: // yearinfo.cnt case 1: // yearinfo.cnt case 1: // yearinfo.cnt case 1: // yearinfo.cnt default: // 2 // dayinfo.cnt}}Copy the code
  • What each item presents
func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? { switch component { case 0: // if row == registerx. year{// Select registerx. year Return yearInfo[row]. Selected} else{// return yearInfo[row]. Normal} case 1: yearInfo[row]. Month {return monthInfo[row]. Selected} else{return monthInfo[row]. Normal} default: Day {return dayInfo[row]. Selected} else{return dayInfo[row]. Normal}}Copy the code

2. Change the data source

 func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {   }
Copy the code

Obviously, the number of days of each month is different, modify the month, the date is also changed

You need to calculate how many days there are in a month

To count days, you need years and months

Points in a leap year

func dayNum(inMonth m: Int, inYear y: Int) -> Int{ var isrunNian = false if y % 4 == 0{ if y % 100 == 0{ isrunNian = (y % 400 == 0) } else{ isrunNian = true }  } switch m{ case 1, 3, 5, 7, 8, 10, 12: return 31 case 4, 6, 9, 11: return 30 default: if isrunNian{ return 29 } else{ return 28 } } }Copy the code

Development, deadline picker

Is to put some restrictions on the data source,

Start with a specific date (today)

Design data structure:

In the information

Year information, the corresponding data structure, is relatively simple

  • Because years can determine months, for example, from May 2022 to 2021

Today is 20210729, there is no May, so the time of month needs to be updated

  • The year could also determine the date, for example, from February 29, 2024, to 2023

From leap years to ordinary years, February has only 28 days,

So the time of day should be updated

  • Months and days do not affect years
Need to find this year
Struct YearX {// let yearInfo: [Int] // let yearInfo: [Int] // let yearInfo: [Int] Int init(){ minYEAR = { () -> Int in let formatter = DateFormatter() formatter.dateFormat = "yyyy" let time = formatter.string(from: Date()) if let t = Int(time){ return t } else{ return 2021 } }() yearInfo = Array(minYEAR... 2030) cnt = yearInfo.count } }Copy the code

On the information

The message of the month, which is relatively simple,

Several components in two groups

  • Full month, 1 to 12

  • The month of this year,

Does not include past months

struct MonthX { let minMonth: Int var monthInfo: [Int] var cnt: Int{ monthInfo.count } init(){ minMonth = { let formatter = DateFormatter() formatter.dateFormat = "MM" let time = formatter.string(from: Date()) if let t = Int(time){ return t } else{ return 7 } }() monthInfo = Array(minMonth... Mutating func reset(){monthInfo = Array(1... Mutating func beCurrent(){monthInfo = Array(minMonth){monthInfo = Array(minMonth... 12)}}Copy the code

Message of the day

To calculate the date, record the currently selected year and month

struct DayX { let minDay: Int var dayInfo: [Int]! Var jahr: Int var moon: Int var CNT: Int{dayinfo.count} var final: Int{dayNum(inMonth: moon, inYear: jahr) } init(jahr y: Int, month m: Int) { jahr = y moon = m minDay = { let formatter = DateFormatter() formatter.dateFormat = "dd" let time = formatter.string(from: Date()) if let t = Int(time){ return t } else{ return 28 } }() dayInfo = Array(minDay... Final)} /// // mutating func reset(month m: Int){moon = m dayInfo = Array(1... Final)} // Mutating func reset(jahr y: Int, month m: Int){ jahr = y moon = m dayInfo = Array(1... // mutating beCurrent from minDay to beCurrent(month m: Int){ moon = m dayInfo = Array(minDay... Final)} // Mutating func beCurrent(jahr y: Int, month m: Int){ jahr = y moon = m dayInfo = Array(minDay... final) } }Copy the code


Added: Modify the data source

You need to make a note of the year, month and day that were previously selected

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { switch component { case 0: // Modify year, The month also changed registerX. Year = row. PickerView reloadComponent (0) if the row = = 0 {monthInfo. BeCurrent ()} else {monthInfo. Reset ()}  registerX.month = min(monthInfo.cnt - 1, registerX.month) pickerView.reloadComponent(1) let lunar = monthInfo[registerX.month].scalar if row == 0, registerX.month == 0{ dayInfo.beCurrent(jahr: yearInfo[0].scalar, month: lunar) } else{ dayInfo.reset(jahr: yearInfo[row].scalar, month: Lunar)} registerX. Day = min (dayInfo. CNT - 1, registerX. Day / / to leap year pickerView reloadComponent (2) case 1: RegisterX / / modify month. The month = row. PickerView reloadComponent. (1) if registerX year = = 0, row = = 0 {dayInfo. BeCurrent (the month: monthInfo[0].scalar) } else{ dayInfo.reset(month: monthInfo[row].scalar) } registerX.day = min(dayInfo.cnt - 1, registerX.day) pickerView.reloadComponent(2) default: / / / / modify day 2 registerX. Day = row. PickerView reloadComponent (2)}}Copy the code

github repo