Many iOS developers started to insert SwiftUI views into existing production projects. UIHostingController
makes it really easy to integrate. Yet sometimes you need it vice versa: insert a UIKit view into SwiftUI view. In FitRadar we provide calendar view to show not only your trainings, but also display other events from calendars on device. Trainers will find it easy to plan, avoid overlapping or help customers not to book training when there is important meeting planned.
This time we use power of UIViewRepresentable
. In this example FSCalendar view (written in Objective-C) needs to be inserted in SwiftUI view, linked with MVC view model. Official documentation is quite laconic about it’s usage. I assume there are many ways how to embedded view behind UIViewRepresentable
structure. Some advice to use Coordinator
. I don’t see big value in it for our case, since I want make this view
reusable and make view model be responsible for calendar view data representation.
Let’s create the “view wrapper” for calendar
import SwiftUI
import FSCalendarstruct CalendarView: UIViewRepresentable {
var calendar: FSCalendar
@Binding var isCalendarExpanded: Bool func makeUIView(context: Context) -> FSCalendar {
calendar
} func updateUIView(_ uiView: FSCalendar, context: Context) {
let scope: FSCalendarScope = isCalendarExpanded ? .month : .week
uiView.setScope(scope, animated: false)
}
}
Normally, you would want to create FSCalendar
inside makeUIView(context:)
but we want keep reference to it, so we create it outside and pass as reference on creation. Another option we pass via binding is calendar mode which is either month view or week view.
After this we may insert in SwiftUI as easy as
CalendarView(calendar: viewModel.calendar,
isCalendarExpanded: $viewModel.isCalendarExpanded)
.frame(maxWidth: .infinity)
.frame(height: viewModel.calendarHeight)
To support this configuration we need a view model
class HomeViewModel: NSObject, ObservableObject {
@Published var calendar = FSCalendar()
@Published var isCalendarExpanded: Bool = true
@Published var calendarHeight: CGFloat = 300.0 override init() {
super.init() calendar.delegate = self
calendar.dataSource = self
calendar.scope = isCalendarExpanded ? .month : .week
calendar.firstWeekday = 2
}
}
That’s it. Please refer to the source code for full example.
References
https://developer.apple.com/documentation/swiftui/uiviewrepresentable
https://github.com/dmi3j/calendar-demo
Txt: https://dmi3j.medium.com/
P.S. Visit our website: https://www.fitradar.me/ and join the mailing list. We are in beta stage already!