SwiftUI集成CalendarKit时数据源与代理方法未调用求助
CalendarKit在SwiftUI中Delegate/DataSource未调用的修复方案
问题原因分析
- Delegate方法签名不匹配:CalendarKit的
DayViewDelegate基于Objective-C实现,要求Swift方法的参数标签与Objective-C选择器完全匹配。你的代码中部分Delegate方法保留了第一个参数的标签(如dayView(dayView: DayView, ...)),导致UIKit无法识别这些方法,进而无法触发回调。 - 事件数据未按日期过滤:
EventDataSource的eventsForDate(_:)协议方法要求返回指定日期的事件,你的代码直接返回所有事件,虽当前模拟事件均为当天,但不符合协议设计逻辑,可能导致后续日期切换时出现异常。
修复步骤
1. 修正Delegate方法签名
将所有DayViewDelegate方法的第一个参数标签改为下划线(_),匹配Objective-C选择器规则,示例如下:
- 原
func dayView(dayView: DayView, didTapTimelineAt date: Date)→ 修改为func dayView(_ dayView: DayView, didTapTimelineAt date: Date) - 原
func dayViewDidBeginDragging(dayView: DayView)→ 修改为func dayViewDidBeginDragging(_ dayView: DayView)
2. 按日期过滤事件
在eventsForDate(_:)方法中,过滤出与传入日期同一天的事件,确保CalendarKit仅显示对应日期的内容:
func eventsForDate(_ date: Date) -> [EventDescriptor] { let calendar = Calendar.current return parent.events.filter { event in calendar.isDate(event.startDate, inSameDayAs: date) || calendar.isDate(event.endDate, inSameDayAs: date) } }
3. 显式设置初始日期
在makeUIViewController中为DayViewController设置初始日期,避免默认日期与模拟事件日期不匹配:
func makeUIViewController(context: Context) -> DayViewController { let viewController = DayViewController() viewController.dataSource = context.coordinator viewController.delegate = context.coordinator viewController.date = Date() // 显式设置初始日期为当前日期 return viewController }
修改后的完整代码
DayViewControllerWrapper.swift
import SwiftUI import CalendarKit struct DayViewControllerWrapper: UIViewControllerRepresentable { @Binding var selectedEvent: Event? @Binding var events: [EventDescriptor] // Callbacks for coordinator delegates var didSelectEventView: ((EventView) -> Void)? var didLongPressEventView: ((EventView) -> Void)? var didTapTimelineAt: ((Date) -> Void)? var didLongPressTimelineAt: ((Date) -> Void)? var didBeginDragging: (() -> Void)? var didTransitionCancel: (() -> Void)? var willMoveTo: ((Date) -> Void)? var didMoveTo: ((Date) -> Void)? var didUpdateEvent: ((EventDescriptor) -> Void)? func makeUIViewController(context: Context) -> DayViewController { let viewController = DayViewController() viewController.dataSource = context.coordinator viewController.delegate = context.coordinator viewController.date = Date() // 显式设置初始日期 return viewController } func updateUIViewController(_ uiViewController: DayViewController, context: Context) { uiViewController.reloadData() } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, EventDataSource, DayViewDelegate { var parent: DayViewControllerWrapper init(_ parent: DayViewControllerWrapper) { self.parent = parent } // MARK: - EventDataSource func eventsForDate(_ date: Date) -> [EventDescriptor] { let calendar = Calendar.current return parent.events.filter { event in calendar.isDate(event.startDate, inSameDayAs: date) || calendar.isDate(event.endDate, inSameDayAs: date) } } // MARK: - DayViewDelegate func dayViewDidSelectEventView(_ eventView: EventView) { parent.selectedEvent = eventView.descriptor as? Event parent.didSelectEventView?(eventView) } func dayViewDidLongPressEventView(_ eventView: EventView) { parent.didLongPressEventView?(eventView) } func dayView(_ dayView: DayView, didTapTimelineAt date: Date) { parent.didTapTimelineAt?(date) } func dayView(_ dayView: DayView, didLongPressTimelineAt date: Date) { parent.didLongPressTimelineAt?(date) } func dayViewDidBeginDragging(_ dayView: DayView) { parent.didBeginDragging?() } func dayViewDidTransitionCancel(_ dayView: DayView) { parent.didTransitionCancel?() } func dayView(_ dayView: DayView, willMoveTo date: Date) { parent.willMoveTo?(date) } func dayView(_ dayView: DayView, didMoveTo date: Date) { parent.didMoveTo?(date) } func dayView(_ dayView: DayView, didUpdate event: EventDescriptor) { parent.didUpdateEvent?(event) } } } struct DayViewControllerWrapper_Previews: PreviewProvider { static var previews: some View { DayViewControllerWrapper(selectedEvent: .constant(nil), events: .constant([])) } }
ContentView.swift
import SwiftUI import CalendarKit struct ContentView: View { @State private var selectedEvent: Event? @State private var events: [EventDescriptor] = [] var body: some View { VStack { Text("My Custom Calendar Example") DayViewControllerWrapper( selectedEvent: $selectedEvent, events: $events, didSelectEventView: { eventView in print("Selected event: \(eventView.descriptor)") }, didLongPressEventView: { eventView in print("Long pressed event: \(eventView.descriptor)") }, didTapTimelineAt: { date in print("Tapped timeline at: \(date)") }, didLongPressTimelineAt: { date in print("Long pressed timeline at: \(date)") }, didBeginDragging: { print("Began dragging") }, didTransitionCancel: { print("Transition canceled") }, willMoveTo: { date in print("Will move to date: \(date)") }, didMoveTo: { date in print("Did move to date: \(date)") }, didUpdateEvent: { event in print("Updated event: \(event)") } ) .frame(height: 400) .onAppear { generateDummyData() } } } private func generateDummyData() { events = [ createEvent(title: "Breakfast at Tiffany's", location: "New York, 5th avenue"), createEvent(title: "Workout", location: "Tufteparken"), createEvent(title: "Meeting with Alex", location: "Home, Oslo, Tjuvholmen"), createEvent(title: "Beach Volleyball", location: "Ipanema Beach, Rio De Janeiro"), createEvent(title: "WWDC", location: "Moscone West Convention Center, 747 Howard St"), createEvent(title: "Google I/O", location: "Shoreline Amphitheatre, One Amphitheatre Parkway"), createEvent(title: "✈️️ to Svalbard ❄️️❄️️❄️️❤️️", location: "Oslo Gardermoen"), createEvent(title: "💻📲 Developing CalendarKit", location: "🌍 Worldwide"), createEvent(title: "Software Development Lecture", location: "Mikpoli MB310, Craig Federighi") ] } private func createEvent(title: String, location: String) -> EventDescriptor { let event = Event() event.startDate = Date() event.endDate = Date().addingTimeInterval(3600) event.text = "\(title)\n\(location)" event.color = .blue event.isAllDay = false event.userInfo = nil return event } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
内容的提问来源于stack exchange,提问作者Jayant Badlani
相关产品推荐
相关产品推荐

