Reputation: 33
Looking for some insight on this. If we for some reason still cannot use .inline
style this way, I wonder what the cleanest option is for apps like mine that populate a text field based on UIDatePicker()
input.
I'm using UIDatePicker()
as the inputView
for UITextField()
. This worked great in older iOS using the .wheels
UIDatePickerStyle()
. The picker would push up from the bottom to display in place of the keyboard, as it still does with other pickers I use elsewhere:
UIPickerView() as UITextField() inputView
However, I got user requests to change to the visual calendar-style .inline
date picker, and I agree this is the right way to go. I use this picker to allow users to define a due date on projects and tasks in a to-do list app.
Unfortunately, the picker does not push the rest of the window contents up the way the .wheels
style does. Instead, it shows as a tiny sliver at the bottom of the screen. You can still tap on the date (barely visible at the bottom) and the calendar picker will overlay correctly. In other words, the picker is usable at a basic level, but it's broken enough I can't release it.
start: text field reads "this project won't expire"
user taps on text field: UIDatePicker() scrunched/truncated at very bottom of screen
user taps on date: picker overlay appears as expected
finish: text field reads "expires November 22, 2023"
Tapping the X to clear the text field will return display state to "start" in that sequence.
I've heard that Apple suggests not using the .inline
style as an inputView
, but I haven't been able to find official confirmation of this or a good reason why. Every other picker view in my app functions this way to provide input for text fields. I don't want to introduce a black sheep with UIDatePicker()
. Also, as my screenshots demonstrate, I use the contents of the UITextField()
to display information in a narrative way to help users understand how to manage their tasks.
In the above screenshots, this class provides a custom date picker to be added to any UITextField()
:
class ExpirationDatePickerGenerator {
static var pickerStyle: UIDatePickerStyle = .inline
static func instantiateExpirationDatePicker(for textField: UITextField, in view: ExpirationDatePickerDelegate) {
let picker = UIDatePicker()
picker.datePickerMode = .date
let calendar = Calendar.autoupdatingCurrent
picker.minimumDate = calendar.date(byAdding: .day, value: 1, to: Date())
picker.addTarget(view, action: #selector(view.userDidSelectDate(_:)), for: .valueChanged)
picker.sizeToFit()
textField.inputView = picker
let inputAccessory = picker.createInputAccessoryViewToolbar(inputView: textField)
textField.inputAccessoryView = inputAccessory
}
}
The following is called by viewDidLoad()
in the view controller:
ExpirationDatePickerGenerator.instantiateExpirationDatePicker(for: expirationDateTextField, in: self)
I thought I was onto something calling picker.sizeToFit()
before assigning it as the textField.inputView
but no dice. Has anyone gotten this to work as a text field input?
Troubleshooting so far:
I've tried defining a custom frame for the picker in the generator, per a suggestion in a similar thread:
let pickerFrame = CGRect(x: textField.frame.minX, y: textField.frame.minY, width: textField.frame.width, height: 150)
I also added picker.sizeToFit()
before assigning to textField.inputView
.
Plus a lot of Googling.
Upvotes: 0
Views: 328
Reputation: 33
While explaining this problem out loud to someone I think I finally have it all figured out. I’ve never seen the actual answer articulated in other threads about this so I’m going to give it my best shot here.
This display behavior is actually correct, and not a bug, at least from the perspective of the .inline
style for UIDatePicker()
.
The .inline
style expects to display the current date value inline, as part of your UI, all the time, unless the user is currently editing the value. Then it displays the appropriate picker per picker.datePickerMode
.
Because this style assumes you’re using it to display the current value whenever the user is not actively using the picker, it is unsuitable as an input view. A good example is the iOS Calendar app. When you create a new event, UIDatePicker()
is displaying the Start and End date/time inline. This inline view is what you can see popping up as the input view in my example. It is displaying “correctly,” i.e. as Apple intended. If the user taps the value way down at the bottom of the screen, the picker opens and behaves as expected.
TL;DR because the .inline
style expects to display information as part of your UI whenever the user is not interacting with UIDatePicker()
, it will display the value, not the picker, as your textField.inputView
. While the user may be able to tap that value (which is shoved all the way at the bottom of the screen) to open the picker and use it to set a new value, the .inline
style really should not be used as an input view.
I hope this saves someone a little time at some point!
Upvotes: 1