It was WWDC22 week, and I was browsing through my Twitter feed to get some updates about the latest Apple APIs. A person tweeted, “No matter how experienced you are as an iOS developer, you’ll always look it up how to set up a date formatter.” So I humorously replied to the tweet by saying, “Dates are hard 😜 .”

After a while, something struck my mind, and I was curious to know if Apple had made improvements to the existing date picker. To my surprise, Apple introduced UICalendarView to create custom calendar views from iOS 16.

At that moment, I could realize how easy it would become for an iOS developer to implement and customize calendar views. Previously, we used third-party calendar components, which came with issues and bugs. Let’s see how to implement a custom native calendar using UICalendarView in iOS 16 and Swift.

Setting up UICalendarView

Setting up UICalendarView

UICalendarView belongs to the UIKit framework and comes with a simple initializer.

let calendarView = UICalendarView()
let gregorianCalendar = Calendar(identifier: .gregorian)
calendarView.calendar = gregorianCalendar

Note: Apple tells us that it is necessary to mention the calendar type explicitly while creating a UICalendarView object. In our example, it will be gregorian calendar.

API availablility: UICalendarView is available from iOS16.0+, iPadOS16.0+, and macCatalyst16.0+

Customizing UICalendarView

Customizing UICalendarView

UICalendarView supports various customizations like setting the background color, setting the view’s corner radius, changing the calendar’s tint color, and many more.

calendarView.backgroundColor = .secondarySystemBackground
calendarView.layer.cornerCurve = .continuous
calendarView.layer.cornerRadius = 10.0
calendarView.tintColor = UIColor.systemTeal

UICalendarView Decorators

UICalendarView Decorators

UICalendarView comes with a UICalendarViewDelegate, which allows us to add date-specific decorations. It will be beneficial while showing free/busy events in a calendar.

Make sure you set the delegate object as well.

calendarView.delegate = self
func calendarView(_ calendarView: UICalendarView, decorationFor dateComponents: DateComponents) -> UICalendarView.Decoration? {
    let font = UIFont.systemFont(ofSize: 10)
    let configuration = UIImage.SymbolConfiguration(font: font)
    let image = UIImage(systemName: "star.fill", withConfiguration: configuration)?.withRenderingMode(.alwaysOriginal)
    return .image(image)
}

In the above example, I have added a yellow star image to all the dates in the calendar. You can write your logic to customize the decorators.

Restricting date selection

Restricting date selection

You can also specify the date ranges that the user can choose. In the above example, you can see that the dates before 12 June 2022 are disabled.

calendarView.availableDateRange = DateInterval.init(start: Date.now, end: Date.distantFuture)

Selection behavior in UICalendarView

There are two types of selection behavior in UICalendarView: Single date selection and multi-date selection. Whether you need a single or multi-date selection must be specified in the selectionBehaviour property of the calendar view.

For single selection

let dateSelection = UICalendarSelectionSingleDate(delegate: self)
calendarView.selectionBehavior = dateSelection

For multi-date selection

let dateSelection = UICalendarSelectionMultiDate(delegate: self)
calendarView.selectionBehavior = dateSelection

Single date selection in UICalendarView

Single date selection in UICalendarView

Single date selection in UICalendarView is done using UICalendarSelectionSingleDateDelegate The delegate provides us with two methods.

func dateSelection(_ selection: UICalendarSelectionSingleDate, didSelectDate dateComponents: DateComponents?) {
    print("Selected Date:", dateComponents)
}

  
func dateSelection(_ selection: UICalendarSelectionSingleDate, canSelectDate dateComponents: DateComponents?) -> Bool {
    return true
}

The didSelectDate method gives us a date whenever the user taps on a date in the UICalendarView.

The canSelectDate method is an optional delegate method using which you can decide whether to allow the user to select a specific date or not.

Multi-date selection in UICalendarView

Multi-date selection in UICalendarView

Multi-date selection in UICalendarView is done using UICalendarSelectionMultiDateDelegate

The delegate provides us with the following methods.

func multiDateSelection(_ selection: UICalendarSelectionMultiDate, didSelectDate dateComponents: DateComponents) {
    print("Selected Date:", dateComponents)
}

The didSelectDate method gives us the selected date by the user.

func multiDateSelection(_ selection: UICalendarSelectionMultiDate, didDeselectDate dateComponents: DateComponents) {
    print("De-Selected Date:", dateComponents)
}

The didDeselectDate method gives us the deselected date by the user.

  
func multiDateSelection(_ selection: UICalendarSelectionMultiDate, canSelectDate dateComponents: DateComponents) -> Bool {
    return true
}
  
func multiDateSelection(_ selection: UICalendarSelectionMultiDate, canDeselectDate dateComponents: DateComponents) -> Bool {
    return true
}

The canSelectDate and canDeseectDate are optional delegate methods using which you can decide whether to allow the user to select/deselect a specific date or not.

Closing thoughts

I see UICalendarView as a considerable improvement when compared to UIDatePicker. I enjoyed exploring the UICalendarView API. I hope you will too. Do share your thoughts about UICalendarView API.

You can find the demo project in here 👉 https://github.com/rizwan95/UICalendarView-Example

References

[1] https://developer.apple.com/documentation/uikit/uicalendarview

[2] https://developer.apple.com/videos/play/wwdc2022/10068/

About the author

Support creators

Show your support to indie devs by downloading their apps from the banner displayed below. It will help them build great apps in these tough times.