截止日期选择器,开发思路

546 阅读3分钟

本文讲, 开发日期选择器的思路

下图为,截止日期选择器

截屏2021-07-29 下午12.03.24.png


开发选择器,就两个点

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)
        }
        
    }

github repo