EventKit with SwiftUI

Beatriz Nakamura Vechiato
2 min readJun 9, 2023

Bridging SwiftUI and KitUI to present a New Event modal in your iOS app.

What you will need

  1. A UIViewController with the EKEventEditViewDelegate
  2. UIViewControllerRepresentable (which converts 1 into a view)
  3. Some way of instantiating 2
  4. Add calendar privacy permissions (Project > Info > Custom iOS Target Properties > add “Privacy — Calendars Usage Description”)

Part 1: The UIViewController

import UIKit
import EventKit
import EventKitUI

class AddEventController: UIViewController, EKEventEditViewDelegate {
let eventStore = EKEventStore()

func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {
controller.dismiss(animated: true, completion: nil)
parent?.dismiss(animated: true, completion: nil)
}

override func viewDidLoad() {
super.viewDidLoad()
eventStore.requestAccess( to: EKEntityType.event, completion: { (granted, error) in
DispatchQueue.main.async {
if (granted) && (error == nil) {
let eventController = EKEventEditViewController()

eventController.eventStore = self.eventStore
eventController.editViewDelegate = self
eventController.modalPresentationStyle = .overCurrentContext
eventController.modalTransitionStyle = .crossDissolve

self.present(eventController, animated: true, completion: nil)
}
}
}
)
}
}

Let’s break it down:

  • EKEventStore will be our point of contact for calendar and reminder data.
  • eventEditViewController() defines how the calendar view is dismissed when the user finishes editing an event.
  • viewDidLoad() overrides the default and isn’t new to UIKit users, we request access to the user’s event store and if granted with no errors, we create an EKEventEditViewController which is the “New Event” view.

EKEventEditViewController also bridges with EKEventEditViewDelegate which we inherit from, without this our event won’t be added to the user’s calendar.

Part 2: The UIViewControllerRepresentable

import SwiftUI

struct AddEvent: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> AddEventController {
return AddEventController()
}

func updateUIViewController(_ uiViewController: AddEventController, context: Context) {
// We need this to follow the protocol, but don't have to implement it
// Edit here to update the state of the view controller with information from SwiftUI
}
}

The trick here is that UIViewControllerRepresentable is a View. Its first function makeUIViewController() is responsible for creating the view controller object and configuring its initial state.

Part 3: Putting it all together

At this point, we have two files, AddEvent.swift and AddEventController.swift.

Using the default ContentView, we create a simple interface with a button which triggers the AddEvent interaction.

import SwiftUI

struct ContentView: View {
@State var showAddEventModal = false

var body: some View {
VStack {

Button {
showAddEventModal.toggle()
} label: {
Text("Add Event")
}

}
.padding()
.sheet(isPresented: $showAddEventModal){
AddEvent()

}
}
}

--

--