本文讲, 开发日期选择器的思路
下图为,截止日期选择器
开发选择器,就两个点
1, 数据源
数据源分,多少栏,一栏多少个,每一个呈现啥内容
- 多少栏
// 3 栏
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 3
}
- 一栏多少个
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
switch component {
case 0:
// 第 1 栏
return yearInfo.cnt
case 1:
// 第 2 栏
return monthInfo.cnt
default:
// 2
// 第 3 栏
return dayInfo.cnt
}
}
- 每一个 item 呈现啥内容
func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? {
switch component {
case 0:
// 第 1 栏
if row == registerX.year{
// 选中,当前
return yearInfo[row].selected
}
else{
// 非当前
return yearInfo[row].normal
}
case 1:
// 第 2 栏
if row == registerX.month{
return monthInfo[row].selected
}
else{
return monthInfo[row].normal
}
default:
// 2
// 第 3 栏
if row == registerX.day{
return dayInfo[row].selected
}
else{
return dayInfo[row].normal
}
}
}
2,改变数据源
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { }
比较明显的是,每个月的天数不同,修改月,把日期也改变了
需要计算每个月,有多少天
算日子,需要年和月
分闰年
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
}
}
}
开发,截止日期选择器
就是对数据源,做一些限制,
从一个具体的日期 ( 今天 ) 开始
设计数据结构:
年的信息
年的信息,对应的数据结构,比较简单
- 因为年可以决定月,例如,从 2022 年 5 月,到 2021 年
今天是 20210729,没 5 月,所以月的时间,要更新
- 年还可以决定日,例如,从 2024 年 2 月 29 日,到 2023 年
从闰年到平年,平年的 2 月只有 28 日,
所以日的时间,要更新
- 月和日,不能作用于年
需要找到今年
struct YearX {
// 找到今年
let minYEAR: Int
// 内容数组
let yearInfo: [Int]
// 内容数组个数
let cnt: 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
}
}
月的信息
月的信息,比较简单,
数组分两组
-
全月,1 ~ 12
-
今年的月份,
不纳入过去的月
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...12)
}
// 全月,1 ~ 12
mutating
func reset(){
monthInfo = Array(1...12)
}
// 这个是,今年的月,
// 不纳入过去的月
mutating
func beCurrent(){
monthInfo = Array(minMonth...12)
}
}
日子的信息
算日子,需要记录当前选中的年和月
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)
}
///
// 非当前年的当前月,就重置日子
// 从 1 到最后一天
mutating
func reset(month m: Int){
moon = m
dayInfo = Array(1...final)
}
// 非当前年的当前月,就重置日子
// 从 1 到最后一天
mutating
func reset(jahr y: Int, month m: Int){
jahr = y
moon = m
dayInfo = Array(1...final)
}
// 当前年的当前月,就设置日子
// 从今天 ( minDay ) 到最后一天
mutating
func beCurrent(month m: Int){
moon = m
dayInfo = Array(minDay...final)
}
// 当前年,就设置日子
// 从今天 ( minDay ) 到最后一天
mutating
func beCurrent(jahr y: Int, month m: Int){
jahr = y
moon = m
dayInfo = Array(minDay...final)
}
}
补充: 修改数据源
需要记录下,之前选中的年月日
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
switch component {
case 0:
// 修改年,把月也给改了
registerX.year = row
pickerView.reloadComponent(0)
if 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) // 为了闰年
pickerView.reloadComponent(2)
case 1:
// 修改月
registerX.month = row
pickerView.reloadComponent(1)
if registerX.year == 0, row == 0{
dayInfo.beCurrent(month: monthInfo[0].scalar)
}
else{
dayInfo.reset(month: monthInfo[row].scalar)
}
registerX.day = min(dayInfo.cnt - 1, registerX.day)
pickerView.reloadComponent(2)
default:
// 修改日
// 2
registerX.day = row
pickerView.reloadComponent(2)
}
}