Reputation: 95
When using the new inline UIDatePicker (Introduced in iOS 14). How can I reset the calendar to current date when no date is already selected.
When running the following, the displayed calendar will reset to the current date WHEN you have selected another date:
self.datePicker.setDate(Date(), animated: true)
However, if you create a new inline UIDatePicker and start scrolling through months, running this same line of code will not update the view until a specific date is selected by the user.
Upvotes: 0
Views: 2282
Reputation: 77433
That's curious...
My guess would be that when using the older "wheel" date picker style, a new date is selected when the wheels stop scrolling... there is no way to "scroll away" from the selected date.
My second guess would be that this issue could be changed ("fixed") in a future iOS update.
Anyway, here is one work-around...
I've only done a quick test of this, so you'll want to thoroughly test it. And probably add some additional checking -- such as what happens if the calendar rolls over midnight while the picker is displayed; how does it look if "today" is the last day of the month; etc.
// 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)
}
Edit - complete example:
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)
}
}
}
Upvotes: 1