You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI集成CalendarKit时数据源与代理方法未调用求助

CalendarKit在SwiftUI中Delegate/DataSource未调用的修复方案

问题原因分析

  1. Delegate方法签名不匹配:CalendarKit的DayViewDelegate基于Objective-C实现,要求Swift方法的参数标签与Objective-C选择器完全匹配。你的代码中部分Delegate方法保留了第一个参数的标签(如dayView(dayView: DayView, ...)),导致UIKit无法识别这些方法,进而无法触发回调。
  2. 事件数据未按日期过滤: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 11:49:52