首页 > 解决方案 > 未选择日期时如何重置内联 iOS UIDatePicker

问题描述

使用新的内联 UIDatePicker(在 iOS 14 中引入)时。当没有选择日期时,如何将日历重置为当前日期。

运行以下命令时,如果您选择了另一个日期,显示的日历将重置为当前日期:

self.datePicker.setDate(Date(), animated: true)

但是,如果您创建一个新的内联 UIDatePicker 并开始滚动月份,则在用户选择特定日期之前,运行同一行代码不会更新视图。

标签: iosswiftxcodeuidatepicker

解决方案


这很好奇...

我的猜测是,当使用较旧的“滚轮”日期选择器样式时,当滚轮停止滚动时会选择一个新日期......没有办法从选定的日期“滚动离开”。

我的第二个猜测是这个问题可能会在未来的 iOS 更新中被改变(“修复”)。

无论如何,这是一种解决方法...

  • 获取今天的日期
  • 从选择器中获取选定的日期
  • 如果它们相同,则用户可能滚动了月/年,所以
    • 在“今天”上加一天
    • 将选择器设置为“明天”(动画)
    • 进行异步调用以将选择器设置为“今天”
  • 如果日期不同,只需将选择器设置为“今天”(动画)

我只是对此进行了快速测试,因此您需要对其进行彻底测试。并且可能会添加一些额外的检查 - 例如如果日历在显示选择器时翻到午夜会发生什么;如果“今天”是本月的最后一天,它看起来如何;等等

    // get "today" date
    let today = Date()

    // get selected date
    let pickerDate = self.datePicker.date
    
    // are the dates the same day?
    let todayIsSelected = Calendar.current.isDate(today, inSameDayAs:pickerDate)

    if todayIsSelected {
        // picker has today selected, but may have scrolled months...

        // should never fail, but this unwraps the optional
        guard let nextDay = Calendar.current.date(byAdding: .day, value: 1, to: today) else {
            return
        }

        // animate to "tomorrow"
        self.datePicker.setDate(nextDay, animated: true)

        // async call to animate to "today"
        DispatchQueue.main.async {
            self.datePicker.setDate(today, animated: true)
        }
    } else {
        // picker has a different date selected
        //  so just animate to "today"
        self.datePicker.setDate(today, animated: true)
    }
    

编辑- 完整示例:

class ScratchVC: UIViewController {
    
    let datePicker = UIDatePicker()
    let btn = UIButton()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if #available(iOS 14.0, *) {
            datePicker.preferredDatePickerStyle = .inline
        } else {
            // Fallback on earlier versions
        }
        
        btn.backgroundColor = .red
        btn.setTitle("Go To Today", for: [])
        btn.setTitleColor(.white, for: .normal)
        btn.setTitleColor(.gray, for: .highlighted)
        
        btn.translatesAutoresizingMaskIntoConstraints = false
        datePicker.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(btn)
        view.addSubview(datePicker)
        
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            
            btn.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            btn.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
            btn.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
            
            datePicker.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 0.9),
            datePicker.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            datePicker.centerYAnchor.constraint(equalTo: g.centerYAnchor),
            
        ])
        
        btn.addTarget(self, action: #selector(didTap(_:)), for: .touchUpInside)
        
    }
    
    @objc func didTap(_ sender: Any) {
        
        // get "today" date
        let today = Date()

        // get selected date
        let pickerDate = self.datePicker.date
        
        // are the dates the same day?
        let todayIsSelected = Calendar.current.isDate(today, inSameDayAs:pickerDate)

        if todayIsSelected {
            // picker has today selected, but may have scrolled months...

            // should never fail, but this unwraps the optional
            guard let nextDay = Calendar.current.date(byAdding: .day, value: 1, to: today) else {
                return
            }

            // animate to "tomorrow"
            self.datePicker.setDate(nextDay, animated: true)

            // async call to animate to "today" - delay for 0.1 seconds
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
                self.datePicker.setDate(today, animated: true)
            })
        } else {
            // picker has a different date selected
            //  so just animate to "today"
            self.datePicker.setDate(today, animated: true)
        }
        
    }
    
}

推荐阅读