iOS DatePicker not setting initial value - ios

I am using storyboards and I have an outlet for the datePicker and I set the date like this in code
let date = NSDate().dateByAddingTimeInterval(-48 * 3600) //meaning 2 days ago the date
datePicker.setDate(date, animated: false)
But when I run the app it always shows the current date

After changing the "Date" property on the storyboard to "Custom" I could set the date on code as I showed above

Related

How to access the iOS 14 time picker in XCUITest

I want to make use of the inline date picker style that was recently introduced in iOS 14. However, I need to make adjustments to a couple of XCUITests that include the previous picker wheel style.
The problem is I can't change the value of the time picker at all. I noticed that the time picker is not a picker nor a pickerWheel element in XCUITest; Instead, it's a textField element.
E.g.
TextField, {{178.3, 401.7}, {74.7, 36.3}}, label: 'Time', value: 12:01
Changing its value like a typical textfield doesn't work at all (typeText doesn't do anything). I tried to access the picker wheels that seem to be inside the textfield, but checking for its descendants returns empty.
po timeInput.descendants(matching: .any).count
t = 799.62s Get number of matches for: Descendants matching type Any
0 // no descendants found
So how do I change the value of the time picker text field in XCUITest?
EDIT:
The date picker mode for the UIDatePicker is set to time, so I'm not really seeing the calendar view, just the time input field.
I put the date picker inside the contentView of a UITableViewCell, which is then added when another table view cell is tapped (i.e. it's dynamically added).
The date picker is configured like this:
picker.datePickerMode = .time
picker.date = Date(timeInterval: time, since: date)
picker.minuteInterval = intervals
if #available(iOS 14, *) {
picker.preferredDatePickerStyle = .inline
}
Previously, the date picker is displayed as a picker wheel and I had no problem accessing it in the XCUITest. I could simply call this to adjust the value of the picker wheel:
pickerWheels.element(boundBy: index).adjust(toPickerWheelValue: value)
However, with the date picker set to inline, the previous query no longer works. I also checked for picker and datePicker elements, but they also return empty results. I can see a textfield element that has a "Time" label and the value contains whatever value is set in the time picker.
(lldb) po app.pickers.count
t = 2270.22s Get number of matches for: Descendants matching type Picker
0 // No results
(lldb) po app.pickerWheels.count
t = 2277.07s Get number of matches for: Descendants matching type PickerWheel
0 // No results
(lldb) po app.datePickers.count
t = 2286.58s Get number of matches for: Descendants matching type DatePicker
0 // No results
(lldb) po app.textFields.count
t = 2302.55s Get number of matches for: Descendants matching type TextField
1 // 1 element matched
(lldb) po app.textFields
t = 2308.08s Requesting snapshot of accessibility hierarchy for app with pid 55829
t = 2308.46s Find: Descendants matching type TextField
t = 2308.47s Requesting snapshot of accessibility hierarchy for app with pid 55829
t = 2308.61s Find: Descendants matching type TextField
t = 2308.61s Requesting snapshot of accessibility hierarchy for app with pid 55829
Find: Target Application
Output: {
Application, pid: 55829, label: 'Projects'
}
↪︎Find: Descendants matching type TextField
Output: {
TextField, {{178.3, 401.7}, {74.7, 36.3}}, label: 'Time', value: 01:00
}
So I can't see any pickers, but I have textfield whose value is set to the date picker's time input value. I tried changing the textfield's value by using typeText but it doesn't seem to do anything at all.
I ended up creating a sample view controller which contains just the UIDatePicker to see if I can access it in XCUITest.
Interestingly, I was able to detect a datePicker element in the XCUITest which is something I wasn't able to do when dynamically adding the UIDatePicker in a table view.
The descendants of the datePicker looks like this:
Find: Descendants matching type DatePicker
Output: {
DatePicker, {{89.3, 423.3}, {196.7, 53.3}}
}
↪︎Find: Descendants matching type Any
Output: {
Other, {{89.3, 423.3}, {196.7, 53.3}}
Other, {{89.3, 431.3}, {196.7, 37.3}}
Other, {{89.3, 431.3}, {196.7, 37.3}}, label: 'Time Picker'
TextField, {{97.3, 431.3}, {74.7, 36.3}}, label: 'Time', value: 05:54
SegmentedControl, {{178.0, 431.3}, {100.0, 36.3}}
Button, {{178.0, 431.3}, {49.0, 36.3}}, label: 'AM'
Button, {{228.0, 431.3}, {50.0, 36.3}}, label: 'PM', Selected
}
The time input field is still a textfield element but I was able to change its value using typeText. I suspect that there's something in our codebase that handles the valueChanged delegate that causes the typeText to not work.
Bottomline, using typeText to change the value of the time input picker should work just fine.
Before using typeText to change its value, make sure it has focus. Try to tap the textfield first, and then the value can be changed via typeText.

Datepicker is returning wrong date when set maximumDate

I have a datepicker where I have set maximumDate as 2 years before
Today is 15/07/2019 so 2 years before it becomes 15/07/2017
Now when I open datepicker, automatically picker goes from today date (15/07/2019) to 15/07/2017 because I have set maximumDate as 2 years before
Now I don't scroll datepicker and click Done button where I read the picker date.
print("mDoneAction===\(mDatePicker.date)")
This print the date as below.
2019-07-15 12:26:17 +0000
Any idea why its giving me 2019 instead of 2017 as picker is already set on 15-07-2017 and not 15-07-2019.
From docs
open var date: Date // default is current date when picker created.
so setting maximumDate doesn't affect date , you need to set date also
let d = UIDatePicker()
let year2Before = Calendar.current.date(byAdding: .year, value:-2, to: Date())!
d.date = year2Before
d.maximumDate = year2Before

How to advance other fields in datePicker automatically?

Let's say that I have a UIDatePicker and the mode is set to .date.
I want the following behaviour:
For example, March has 30 days. If I scroll below the 30th day, I want the month to be automatically incremented to April and so on.
Is there a property that does just that? I couldn't find one.
Thanks.
I don't think there's any way to do what you want with a normal UIDatePicker. You could attach an action to the valueChanged event, but that doesn't get called until the date picker stops moving.
You could probably create a custom date picker using a standard UIPickerView. You could use the data source methods to figure out when the "wheels" are turned, call selectedRow(inComponent:) to figure out which values are selected for each wheel, and then call selectRow(_:inComponent:animated) to switch the month if the user scrolls the day past the end of the month.
How to advance other fields in datePicker automatically?
The best way to do this is using the Target-Action design pattern. Basically, when a user chooses a new date (action), the view (a target) does something.
Here's some code that changes the day value to 1 if it's set to 0:
override func viewDidLoad() {
...
let datePicker = UIDatePicker()
datePicker.datePickerMode = .date
datePicker.addTarget(self, action: #selector(doStuff(sender:)), for: UIControlEvents.valueChanged)
view.addSubview(datePicker)
...
}
#IBAction func doStuff(sender: UIDatePicker) {
let calendar = Calendar.current
let components = calendar.dateComponents([.day], from: sender.date)
if components.day == 0 {
// Using Calendar.current automatically takes care of Time Zones for us.
if let date = calendar.date(byAdding: .day, value: 1, to: sender.date) {
sender.setDate(date, animated: true)
}
}
}
Note: This example is in Swift 4.
No, there is no property that does this that I am aware of.

iOS UIDatePicker display without time

I would like to have a Date Picker with only one wheel, filled with days as on the Date and Time mode.
If I choose the Date mode, I have 3 wheels and I loose the name of the day.
In fact I would like something like the date and time mode, but only with the date.
I could use a UIPickerView, but I would have to fill it by myself with a very big array of data, as I want to be able go back far in time. With the Date picker, it's filled automatically, which is cool.
Is there a solution ?
You can also use UIDatePicker's pickerMode property to do that.
datePicker.pickerMode = .Date
Look into header file, you will see that there are few other Options that you can play with. Other values are;
Time
Date
DateAndTime
CountDownTimer
You should use the UIPickerView instead of the UIDatePicker. There is no possibility to customise UIDatePicker in the way you want.
try displayedComponents with .date
DatePicker( selection: .constant(futureDate), displayedComponents: [.date],
label: { Text("Due date") })
As you only need to show the contents that you have marked in the green box. You can use this https://github.com/attias/AADatePicker and modify it a bit and you can get it as per your requirement.
The changes you will need to make are within the AADatePickerView Class
1) In viewForRow method comment the following things
2) Second change
datePicker.datePickerMode = UIDatePicker.Mode.date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd MMMM yyyy"
let selectedDate = dateFormatter.string(from: datePicker.date)
print(selectedDate)

iOS UIDatePicker always returns today's date

There is similar question on Stack Overflow, but the problem there was different then mine, so I feel free to open this one.
I have iOS view controller with a UIDatePicker defined in storyboard.
I have defined(connected) IBOutlet in view controller code like this:
#IBOutlet weak var endTimeDatePicker: UIDatePicker!
At one point I set initial date like this:
endTimeDatePicker.date = state!.endTime;
or like this:
endTimeDatePicker.setDate(state!.endTime, animated: true);
and it shows correct date indicating that date picker is connected correctly.
But then, if I pick another date and try to get selected date with endTimeDatePicker.date it always returns the same - today's date, no matter what I pick.
Storyboard properties for date picker are:
Mode - Date and Time
Interval - 1 minute
Date - Current Date (but it's the same with custom, only returning defined custom date every time)
Is there something that I've missed to do?
I don't have for sure two different datePickers (like in potential duplicate Stack Overflow questions)
EDIT: looks like it only happens when Date Picker has set initial value from code.
EDIT: code that sets Date Picker:
private func reloadData (state : State?)
{
if (state != nil)
{
endTimeDatePicker.setDate(state!.endTime, animated: true);
backgroundImage.image = UIImage(named: state!.type.imageName)!;
}
else
{
let endDate = NSDate(timeIntervalSinceNow: 1800);
endTimeDatePicker.setDate(endDate, animated: true);
backgroundImage.image = UIImage(named: StateType.Active.imageName);
}
}
Code that tries to read selected date:
#IBAction func doneTapped(sender: AnyObject) {
let row: Int = self.stateTypePicker.selectedRowInComponent(0);
state = State (id: -1, type: stateTypes[row], startTime: NSDate(), endTime: self.endTimeDatePicker.date);
service.addState(state!) {
(responseDict) in
}
}
func reloadData is called in callback for http request. Could be thread lock problem maybe?
Your issue is related to the callback method reloadData from the NSURLSession. In here, you are updating the UIDatePicker in a background thread, but all UI updates have to be done on the main thread.
This is the reason why you are seeing todays date, when you are reading the date property of the UIDatePicker.

Resources