Kazuya Fujimoto
Kazuya Fujimoto

Reputation: 93

SwiftUI - Change CalendarType of KVKCalendar

I'm trying to build a calendar app for iOS using KVKCalendar but it's not originally build for Swift UI so I'm kind of struggling to achieve what I want to do.

My goal is changing calendar type (such as daily, weekly, monthly) by a segment controller, exactly like this example (which is already provided in git repository). sampleUI

So far, I managed to display daily style calendar view as default. But I don't know how I can change its calendar type from ContentView.swift

Does anyone know about this type of ViewController ↔ Swift UI thing?

My code

My ContentView.swift is like this

import SwiftUI
import KVKCalendar
struct ContentView: View {
    @State var events: [Event] = []
    @State var selectedType: CalendarType = .week // I want this to change its calendar type.      
    var body: some View {
        VStack{
            CalendarDisplayView(events: $events)
        }
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

And my ContentDisplayView.swift is like this

import SwiftUI
import EventKit
import KVKCalendar

struct CalendarDisplayView: UIViewRepresentable {

    @Binding var events: [Event]
    
    public init(events: Binding<[Event]>) {
        self._events = events
    }
    
    private var calendar: CalendarView = {
        var style = Style()
        if UIDevice.current.userInterfaceIdiom == .phone {
            style.timeline.widthTime = 40
            style.timeline.currentLineHourWidth = 45
            style.timeline.offsetTimeX = 2
            style.timeline.offsetLineLeft = 2
            style.headerScroll.titleDateAlignment = .center
            style.headerScroll.isAnimateTitleDate = true
            style.headerScroll.heightHeaderWeek = 70
            style.event.isEnableVisualSelect = false
            style.month.isHiddenTitle = true
            style.month.weekDayAlignment = .center
        } else {
            style.timeline.widthEventViewer = 350
            style.headerScroll.fontNameDay = .systemFont(ofSize: 17)
        }
        style.month.autoSelectionDateWhenScrolling = true
        style.timeline.offsetTimeY = 25
        style.startWeekDay = .monday
        style.timeSystem = .current ?? .twelve
        style.systemCalendars = ["Calendar"]
        if #available(iOS 13.0, *) {
            style.event.iconFile = UIImage(systemName: "paperclip")
        }
        style.locale = Locale.current
        style.timezone = TimeZone.current
        return CalendarView(frame: UIScreen.main.bounds, style: style)
    }()
        
    func makeUIView(context: UIViewRepresentableContext<CalendarDisplayView>) -> CalendarView {
        calendar.dataSource = context.coordinator
        calendar.delegate = context.coordinator
        calendar.reloadData()
        return calendar
    }
    
    func updateUIView(_ uiView: CalendarView, context: UIViewRepresentableContext<CalendarDisplayView>) {
       context.coordinator.events = events
   }
    
    func makeCoordinator() -> CalendarDisplayView.Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, CalendarDataSource, CalendarDelegate {
        private let view: CalendarDisplayView
        
        var events: [Event] = [] {
            didSet {
                view.calendar.reloadData()
            }
        }
        
        init(_ view: CalendarDisplayView) {
            self.view = view
            super.init()
        }
        
        func eventsForCalendar(systemEvents: [EKEvent]) -> [Event] {
            return events
        }
    }
    
}

Upvotes: 1

Views: 756

Answers (1)

aheze
aheze

Reputation: 30318

First, add a @Binding inside CalendarDisplayView so it can update:

@Binding var selectedType: CalendarType

Then, pass in ContentView's $selectedType for CalendarDisplayView's selectedType, just like how you passed in $events.

                                     /// here!
CalendarDisplayView(events: $events, selectedType: $selectedType)

Finally, update the type inside updateUIView, which is called whenever the @Binding changes.

func updateUIView(_ uiView: CalendarView, context: UIViewRepresentableContext<CalendarDisplayView>) {
    context.coordinator.events = events

    calendar.set(type: selectedType, date: Date()) /// I've never used this library, so you might need to replace `Date()` with something else
    calendar.reloadData()
}

Upvotes: 2

Related Questions