How to use EKCalendarChooser with SwiftUI

Short post showing how to bridge this controller with SwiftUI and get selected calendars.

Just like other UIKit controllers EKCalendarChooser, which lets users select their calendars, for use in your app needs a small wrapper around it with the UIViewControllerRepresentable protocol.

This code below is intended as a starting point for folks who need to work with EKCalendarChooser in their SwiftUI project.

Big thanks to Paul Hudson for this guide about using UIImagePickerController with SwiftUI which served as an inspiration.

Complete code

So here is the code:

import SwiftUI
import EventKitUI

struct CalendarChooser: UIViewControllerRepresentable {
    func makeCoordinator() -> Coordinator {
        return Coordinator(self)
    }

    @Environment(\.presentationMode) var presentationMode
    @Binding var calendars: Set<EKCalendar>?

    let eventStore: EKEventStore

    func makeUIViewController(context: UIViewControllerRepresentableContext<CalendarChooser>) -> UINavigationController {
        let chooser = EKCalendarChooser(selectionStyle: .multiple, displayStyle: .allCalendars, entityType: .event, eventStore: eventStore)
        chooser.selectedCalendars = calendars ?? []
        chooser.delegate = context.coordinator
        chooser.showsDoneButton = true
        chooser.showsCancelButton = true
        return UINavigationController(rootViewController: chooser)
    }

    func updateUIViewController(_ uiViewController: UINavigationController, context: UIViewControllerRepresentableContext<CalendarChooser>) {
    }

    class Coordinator: NSObject, UINavigationControllerDelegate, EKCalendarChooserDelegate {
        let parent: CalendarChooser

        init(_ parent: CalendarChooser) {
            self.parent = parent
        }

        func calendarChooserDidFinish(_ calendarChooser: EKCalendarChooser) {
            parent.calendars = calendarChooser.selectedCalendars
            parent.presentationMode.wrappedValue.dismiss()
        }

        func calendarChooserDidCancel(_ calendarChooser: EKCalendarChooser) {
            parent.presentationMode.wrappedValue.dismiss()
        }
    }
}

Example usage

Sample usage can look something like this:

.sheet(isPresented: $showingCalendarChooser) {
    CalendarChooser(calendars: self.$eventsRepository.selectedCalendars, eventStore: self.eventsRepository.eventStore)
}

You need to pass in Binding for selected calendars and also instance of EKEventStore.

I am using this definition for selectedCalendars:

@Published var selectedCalendars: Set<EKCalendar>?

More EventKit resources

For more on EventKit check out other posts in this series or my example project on GitHub.

Uses: Xcode 12 & Swift 5.3

Filip Němeček profile photo

WRITTEN BY

Filip Němeček @nemecek_f

iOS blogger and developer with interest in Python/Django. Telling other devs' stories with iOS Chat.