Enable next 7day in datepicker in swift - ios

I have implemented date picker in swift. I want to enable the date for next 7 day in calendar.How its is Possible.

You can set a maximum date within a UIDatePicker like this:
var datePicker = UIDatePicker()
datePicker.datePickerMode = .date
// set the start date to today if you don't want to allow dates in the past
datePicker.minimumDate = Date()
// calculate +7 days
let next7Days = Calendar.current.date(byAdding: .day, value: 7, to: Date())
//set maximum date
datePicker.maximumDate = next7Days
this will only allow to chose a date within the next 7 days

Related

iOS UIDatePicker "Time" label locale / language not working

Is there any way to change the language/locale of the label with "Time" string on UIDatePicker? This is my date picker configuration:
datePicker.locale = Locale(identifier: "de_DE")
datePicker.calendar.locale = Locale(identifier: "de_DE")
datePicker.datePickerMode = .dateAndTime
datePicker.preferredDatePickerStyle = .inline
And it is displayed as on the screenshot:
As you can see the "Time" label is still in English but I expected it to be in German. Is there any way to fix that or maybe at least hide this label?

UIDatePicker max and min date range

I develop my own app and I work on sign up screen.The person who sign up my app have to enter a birth date in my textfield and only user has 18-55 age accept.My textField has UIDatePicker.When datePicker open ,I want to show min and max date range.For example today now 12/02/2022 , datePicker have to show min date 12/02/2004 (user has 18) and show max date 1/1/1967 (user has 55).
https://imgur.com/a/DBpT5eq
first change the version checking line to
if #available(iOS 13.4,*) {
}
secondly use calendar for min max date
let datePicker = UIDatePicker()
if let eighteenAgo = Calendar.current.date(byAdding: .year, value: -18, to: Date()),
let afterFiftyFive = Calendar.current.date(byAdding: .year, value: 55, to: Date()) {
print(eighteenAgo.formatted(), ": Min")
print(afterFiftyFive.formatted(), ": Max")
datePicker.minimumDate = eighteenAgo
datePicker.maximumDate = afterFiftyFive
}

How do I set a datePicker's display to an AppStorage time (hour, min) settings?

I'm trying to allow the user to select what time they want a notification to go off through time selection on a datePicker. I have a datePicker set to only display the time as follows:
DatePicker("First Workout Notification Time", selection: $firstNotificationTime, displayedComponents: .hourAndMinute)
I want the firstNotificationTime #State var to use my #AppStorage time vars which are set as defaults on this page above the "var body: some View" as:
#AppStorage("startNoficationHour") var startNoficationHour: Int = 9
#AppStorage("startNoficationMin") var startNoficationMin: Int = 30
When the view loads (i.e. .onAppear(){}) I want the datePicker's $firstNotificationTime to get set to the startNoficationHour and startNoficationMin
my view is set up as follows:
var body: some View {
VStack {
DatePicker("First Workout Notification Time", selection: $firstNotificationTime, displayedComponents: .hourAndMinute)
}
}
.onAppear(){
// set datePicker's fisrtNotificationTime to startNotificationHour and startNotificationMin
let components = DateComponents(calendar: Calendar.current, timeZone: TimeZone.current, hour:startNoficationHour, minute: startNoficationMin)
firstNotificationTime = components.date!
print("start hour is \(startNoficationHour) and start minute is \(startNoficationMin)")
}
.onDisappear(){
// sets startNotificationHour and startNotificationMin to datePicker
let components = Calendar.current.dateComponents([.hour, .minute], from: firstNotificationTime)
startNoficationHour = components.hour!
startNoficationMin = components.minute!
print("start hour is set to \(startNoficationHour) and start minute is set to \(startNoficationMin)")
}
ok so all I had to do was set a component variable to the hour and minute and place that in the onAppear
let components = DateComponents(calendar: Calendar.current, timeZone: TimeZone.current, hour:startNoficationHour, minute: startNoficationMin)
firstNotificationTime = components.date!
I updated my question above with the answer which was based on the comment from Tushar Sharma above that linked to this Set default date on DatePicker in SwiftUI?
You are doing so much thing. There is easy solution. Use a shadow property.
Date has a method that convert the time into a double value. So, you can store the double value into #AppStorage and use it to update the date.
Here is an example,
Create a #State date variable,
#State var reminderTime = Date()
Create a show property save the date.
#AppStorage("reminderTime") var reminderTimeShadow: Double = 0
Now in the DatePicker,
DatePicker("", selection: Binding(
get: {reminderTime}, set: {
reminderTimeShadow = $0.timeIntervalSince1970
reminderTime = $0
setNotification()
}), displayedComponents: .hourAndMinute)
.onAppear {
reminderTime = Date(timeIntervalSince1970: reminderTimeShadow)
}
Here, you use the explicit binding to get and set the value and when setting the value of reminderTime, you also set the value reminderTimeShadow and save it by #AppStorage and use this in .onAppear by using reminderTime = Date(timeIntervalSince1970: reminderTimeShadow) thus update reminderTime and the view.

Change UITableViewCell Height based UICollectionView content size height

I'm working on a calendar created with a UICollectionView.
The UICollectionView is located inside a UITableViewCell
The UITableViewCell in the heightForRowAt method return UITableView.automaticDimension
The UICollectionView used to create the calendar updates its height based on how many days are shown, for example the month of November has its first day which falls on Sunday so to place the day under the label "Sunday" the collectionView must necessarily add a whole line.
Normally each month has 5 rows (week) but when the first day of the month happens on Sunday the collectionview returns 6
Now as I said I was able to update the height of the UICollectionView based on how many rows it returns but I cannot dynamically change the height of the TableViewCell that contains the collectionView
How can I resize the tableViewCell based on the height of the CollectionView within it?
EDIT
my cell
I have set UITableView.automaticDimension for the height of the cell that contains the CalendarView
In the class CalendarView: UIView I created a variable CGFloat calendarH to set the default height of the collectionView
CollectionView implementation
I have added an observer which tracks the height of the collctionView when it changes
I am currently able to change the height of the collectionView but its superview (bookingCalendarView) and the tableView cell continue to remain with a fixed height and do not adapt to the collectionView
You need to create an #IBOutlet for your collection view's height constraint.
When you set a row's calendar / month data, determine whether you need 5 or 6 rows.
If it's 6, set the .constant on the height constraint to 750
If it's 5, set the .constant on the height constraint to 675
Edit
First, I'm going to suggest you forget about using a "self-sizing" collection view. UICollectionView is designed to lay out cells based on the size of the collection view, providing automatic scrolling when there are too many cells.
Trying to "self-size" it may work in one instance, but fail in another. The reason it fails in this case is because your table view lays out the cell and calculates its height before the collection view is populated, and thus before it can "self-size."
Instead, since you know your cell Height is 75, you can calculate how many rows your calendar will need and either set the .constant on a height constraint for your collection view, or (since you're already using heightForRowAt) calculate the row height there.
Look at this code:
let dateComponents = DateComponents(year: year, month: month)
// startDate will be the first date of the month (Jan 1, Feb 1, Mar 1, etc...)
guard let startDate = calendar.date(from: dateComponents) else {
fatalError("Something is wrong with the date!")
}
// get the range of days in the month
guard let range = calendar.range(of: .day, in: .month, for: startDate) else {
fatalError("Something is wrong with the date!")
}
// get number of days in the month
let numberOfDaysInMonth = range.count
// get the day of the week for the first date in the month
// this returns 1-based numbering
// Nov 1, 2020 was a Sunday, so this would return 1
let startDayOfWeek = Calendar.current.component(.weekday, from: startDate)
// add the "leading days to the start date"
// so, if startDayOfWeek == 3 (Tuesday)
// we need to add 2 "empty day cells" for Sunday and Monday
let totalCellsNeeded = numberOfDaysInMonth + (startDayOfWeek - 1)
// calculate number of rows needed -- this will be 4, 5 or 6
// the only time we get 4 is if Feb 1st in a non-leapYear falls on a Sunday
let numRows = Int(ceil(Double(totalCellsNeeded) / Double(7)))
// we now know the Height needed for the collection view
// you said your calendar cell height is 75, so...
// cvHeight = numRows * 75
We can put that in a loop and print() the information to the debug console like this:
override func viewDidLoad() {
super.viewDidLoad()
let calendar = Calendar.current
// 2026 is the next year where Feb starts on a Sunday
// so let's use that year to see that we get 4 rows for Feb
let year = 2026
for month in 1...12 {
let dateComponents = DateComponents(year: year, month: month)
// startDate will be the first date of the month (Jan 1, Feb 1, Mar 1, etc...)
guard let startDate = calendar.date(from: dateComponents) else {
fatalError("Something is wrong with the date!")
}
// get the range of days in the month
guard let range = calendar.range(of: .day, in: .month, for: startDate) else {
fatalError("Something is wrong with the date!")
}
// get number of days in the month
let numberOfDaysInMonth = range.count
// get the day of the week for the first date in the month
// this returns 1-based numbering
// Nov 1, 2020 was a Sunday, so this would return 1
let startDayOfWeek = Calendar.current.component(.weekday, from: startDate)
// add the "leading days to the start date"
// so, if startDayOfWeek == 3 (Tuesday)
// we need to add 2 "empty day cells" for Sunday and Monday
let totalCellsNeeded = numberOfDaysInMonth + (startDayOfWeek - 1)
// calculate number of rows needed -- this will be 4, 5 or 6
// the only time we get 4 is if Feb 1st in a non-leapYear falls on a Sunday
let numRows = Int(ceil(Double(totalCellsNeeded) / Double(7)))
// we now know the Height needed for the collection view
// you said your calendar cell height is 75, so...
// cvHeight = numRows * 75
// debug output
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEEE"
let dayName = dateFormatter.string(from: startDate)
dateFormatter.dateFormat = "LLLL y"
let dateString = dateFormatter.string(from: startDate)
let dayPadded = dayName.padding(toLength: 10, withPad: " ", startingAt: 0)
let datePadded = dateString.padding(toLength: 16, withPad: " ", startingAt: 0)
print("\(datePadded) has \(numberOfDaysInMonth) days, starting on \(dayPadded) requiring \(numRows) rows")
}
}
Here's the output:
January 2026 has 31 days, starting on Thursday requiring 5 rows
February 2026 has 28 days, starting on Sunday requiring 4 rows
March 2026 has 31 days, starting on Sunday requiring 5 rows
April 2026 has 30 days, starting on Wednesday requiring 5 rows
May 2026 has 31 days, starting on Friday requiring 6 rows
June 2026 has 30 days, starting on Monday requiring 5 rows
July 2026 has 31 days, starting on Wednesday requiring 5 rows
August 2026 has 31 days, starting on Saturday requiring 6 rows
September 2026 has 30 days, starting on Tuesday requiring 5 rows
October 2026 has 31 days, starting on Thursday requiring 5 rows
November 2026 has 30 days, starting on Sunday requiring 5 rows
December 2026 has 31 days, starting on Tuesday requiring 5 rows
So... either in:
cellForRowAt ... calculate the needed height and set the CV height in the cell, or
heightForRowAt ... calculate and return the needed height for the row
Side note: I'd suggest using auto-layout for all of your cells, instead of returning various row heights.

Refresh UIDatePicker disabled dates color

Description
I have UIDatePicker with datePickerMode set to date, minimumDate and maximumDate are also set. Dates that are after maximumDate are disabled and with different color to indicate that they cannot be selected.
Code for UIDatePicker
let datePicker = UIDatePicker()
datePicker.minimumDate = Date.init(timeIntervalSince1970: 0)
datePicker.maximumDate = Date()
datePicker.setValue(UIColor.yellow, forKeyPath: "textColor")
datePicker.datePickerMode = .date
Disabled future dates
When year is changed to year in the past it's expected that month and date are refreshed and color is changed, which is not the case.
Notice how 2018 has yellow color indicating that it can be selected but August and 26 do not have that color like they are not selectable. But when I scroll to them they will change color to yellow since year is 2017.
Question
How to refresh disabled date picker components when date picker changes value?
The only solution I found is switching datePickerMode to another and switching it back. It works but breaks picker animations :/
#IBAction private func datePickerChangedAction(_ sender: Any) {
self.datePicker.datePickerMode = .dateAndTime
self.datePicker.datePickerMode = .date
// ...
}

Resources