How to use UICalendarView in iOS
Look at setting up the proper calendar view with selections and customizations.
Published: June 16, 2022 Sponsored I want a Press KitSince iOS 16, we can use a dedicated calendar view to let users select dates in a way that offers more control than with the standard UIDatePicker
.
UICaledarView
looks similar to the modern UIDatePicker
introduced with iOS 14. This blog post is intended to get you started quickly.
We will look at:
- How to start using the calendar view
- How to select a single date
- How to select multiple dates
- How to disable selection for specific dates
- How to decorate days in the calendar with images, colors, or custom views
Basic setup
UICalendarView
is a standard UIKit view, so we can use it freely. Note that it is not available in the Interface Builder library. So if you are using Storyboards, you will need to set up a container view for it and initialize it in code.
Start by creating an instance:
let calendarView = UICalendarView()
And then configure it for your needs:
let gregorianCalendar = Calendar(identifier: .gregorian)
calendarView.calendar = gregorianCalendar
It defaults to Calendar.current
but we can set it always to be gregorian calendar for greater control.
Further, you can customize locale
, timeZone
, and fontDesign
where the .rounded
option looks pretty nice.
And of course, the tintColor
to change the default blue look.
calendarView.tintColor = .systemMint
You can also restrict the available dates with the availableDateRange
property. This can be easily created using two dates, like this:
calendarView.availableDateRange = DateInterval(start: .now, end: .distantFuture)
And the result:
Selecting single date
Selection in the UICalendarView
is handled via selectionBehavior
property, and each has a dedicated delegate.
To let user select single date, we first setup the selection behavior:
let selection = UICalendarSelectionSingleDate(delegate: self)
calendarView.selectionBehavior = selection
And implement the delegate requirements. Only one method is required.
extension ViewController: UICalendarSelectionSingleDateDelegate {
func dateSelection(_ selection: UICalendarSelectionSingleDate, didSelectDate dateComponents: DateComponents?) {
print(dateComponents)
}
}
And with this, you have a calendar view where the user can select a single date.
How to disable selection of certain dates
If you want to prevent the user from ever selecting certain dates, for example when tickets for given day are sold out, there is the second and last method from the UICalendarSelectionSingleDateDelegate
:
func dateSelection(_ selection: UICalendarSelectionSingleDate, canSelectDate dateComponents: DateComponents?) -> Bool {
return true
}
If you return false
for any of the dateComponents
parameter, the day in the calendar view is greyed out and cannot be selected.
This gives you more flexibility than the limited date range with availableDateRange
.
Selecting multiple dates
Multi-select works similarly to a single selection, we need to implement different delegate and a couple of methods.
Start by configuring the selection:
let multiSelect = UICalendarSelectionMultiDate(delegate: self)
calendarView.selectionBehavior = multiSelect
And next, we need this delegate: UICalendarSelectionMultiDateDelegate
It requires two methods - we have to handle new selection and deselection.
extension ViewController: UICalendarSelectionMultiDateDelegate {
func multiDateSelection(_ selection: UICalendarSelectionMultiDate, didSelectDate dateComponents: DateComponents) {
}
func multiDateSelection(_ selection: UICalendarSelectionMultiDate, didDeselectDate dateComponents: DateComponents) {
}
}
And once again, we can also limit selection and also deselection. If you wanted to prevent the user from deselecting certain dates.
func multiDateSelection(_ selection: UICalendarSelectionMultiDate, canSelectDate dateComponents: DateComponents) -> Bool {
guard let day = dateComponents.day else {
return false
}
return day.isMultiple(of: 2)
}
func multiDateSelection(_ selection: UICalendarSelectionMultiDate, canDeselectDate dateComponents: DateComponents) -> Bool {
return dateComponents.day != 14
}
My example implementation allows the selection of even days and doesn’t allow the user to deselect the 14th day.
Programmatic selection
Chances are, you would want to pre-select some dates for the user. UICalendarView
has got you covered. Or instead, the available selections do, since you won’t find any setSelectedDate
on the UICalendarView
.
These methods are available on the UICalendarSelectionSingleDate
and UICalendarSelectionMultiDate
.
For the first one you can call setSelected
with a single instance of DateComponents
and for the multi-select, there is setSelectedDates
. Both allow you to animate this optionally.
To scroll to particular dates, you can also use setVisibleDateComponents
on the UICalendarView
.
Showing custom information in calendar view
And lastly, let’s look at how we can show additional information in the calendar view. Suppose you are making an app to book hotel stays. For example, you could use an indicator to show which dates offer the best price. Or something similar.
And of course, the classic example shows which days have any events.
To show custom decorations - the official term for these - you need to implement the UICalendarViewDelegate
protocol.
calendarView.delegate = self
And it has a single method that can optionally return decoration of type UICalendarView.Decoration
.
This can be a simple colored dot with a specified size, UIImage
(SF Symbols work great here) or a completely custom UIView
subclass.
extension ViewController: UICalendarViewDelegate {
func calendarView(_ calendarView: UICalendarView, decorationFor dateComponents: DateComponents) -> UICalendarView.Decoration? {
guard let day = dateComponents.day else {
return nil
}
if !day.isMultiple(of: 2) {
return UICalendarView.Decoration.default(color: .systemGreen, size: .large)
}
return nil
}
}
I am once again using super simple rules to show the decorations. In an actual project, you would consult your data source and either show decorations or not based on some condition.
What about selecting date ranges?
I mentioned as an example an app that would let users select dates for upcoming hotel stays. In such cases, you would typically select the start and end dates which the UICalendarView
does not really support out of the box.
I guess the reason might be we already have UIDatePicker
, but I plan to hopefully explore using this new component for date ranges soon and write about it.
What about SwiftUI?
Unfortunately, this component does not have SwiftUI counterpart, so you will have to wrap it in the UIViewRepresentable
.
Are you interested in more “calendar stuff”? I have entire series dedicated to EventKit framework, which lets developers read events from the iOS calendar and create a new one, work with reminders, and more.