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

UICalendarView集成CoreData:装饰显示与日期跳转问题求助

问题解答

1. 解决CoreData数据传入日历的报错并实现条件装饰

原代码的错误在于Coordinator对FetchedResults<Item>的类型处理错误,无需将其包装为ObservedObject,直接通过父视图访问或正确传递实例即可。以下是修正后的完整代码:

修正后的CalendarHelper

import SwiftUI
import CoreData

struct CalendarHelper: UIViewRepresentable {
    
    @Environment(\.managedObjectContext) private var viewContext
    @FetchRequest(
        sortDescriptors: SleepSort.default.descriptors,
        animation: .default)
    private var items: FetchedResults<Item>
    
    let interval: DateInterval
    // 绑定选中日期,用于传递给上层视图
    @Binding var selectedDate: Date?
    
    func makeUIView(context: Context) -> UICalendarView {
        let calView = UICalendarView()
        calView.delegate = context.coordinator
        calView.calendar = Calendar(identifier: .gregorian)
        calView.availableDateRange = interval
        calView.fontDesign = .rounded
        let dateSelection = UICalendarSelectionSingleDate(delegate: context.coordinator)
        calView.selectionBehavior = dateSelection
        calView.wantsDateDecorations = true
        return calView
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
    
    func updateUIView(_ uiView: UICalendarView, context: Context) {
        // CoreData数据变化时刷新日历装饰
        uiView.reloadDecorations(forDateComponents: nil, animated: true)
    }
    
    class Coordinator: NSObject, UICalendarViewDelegate, UICalendarSelectionSingleDateDelegate {
        var parent: CalendarHelper
        
        init(parent: CalendarHelper) {
            self.parent = parent
        }
        
        @MainActor
        func calendarView(_ calendarView: UICalendarView, decorationFor dateComponents: DateComponents) -> UICalendarView.Decoration? {
            guard let currentDate = dateComponents.date else { return nil }
            
            // 判断当前日期是否存在CoreData条目
            let calendar = Calendar.current
            let hasMatchingItem = parent.items.contains { item in
                guard let itemDate = item.date else { return false }
                return calendar.isDate(itemDate, inSameDayAs: currentDate)
            }
            
            // 仅存在数据时显示装饰
            guard hasMatchingItem else { return nil }
            
            let font = UIFont.systemFont(ofSize: 10)
            let configuration = UIImage.SymbolConfiguration(font: font)
            let image = UIImage(systemName: "star.fill", withConfiguration: configuration)?.withRenderingMode(.alwaysOriginal)
            return .image(image)
        }
        
        func dateSelection(_ selection: UICalendarSelectionSingleDate, didSelectDate dateComponents: DateComponents?) {
            // 将选中日期传递给父视图
            parent.selectedDate = dateComponents?.date
        }
        
        func dateSelection(_ selection: UICalendarSelectionSingleDate, canSelectDate dateComponents: DateComponents?) -> Bool {
            return true
        }
    }
}

修改要点:

  • 移除Coordinator中错误的@ObservedObject var items: Item定义,通过parent.items直接访问CoreData数据
  • 在updateUIView中添加装饰刷新逻辑,确保数据变化时日历同步更新
  • 在decorationFor方法中添加日期匹配逻辑,仅当对应日期存在Item时显示装饰

2. 实现选中日期跳转详情视图

通过@Binding将选中日期从CalendarHelper传递到CalView,结合SwiftUI的导航组件实现跳转:

修正后的CalView

import SwiftUI
import CoreData

struct CalView: View {
    // 存储选中的日期
    @State private var selectedDate: Date?
    
    var body: some View {
        NavigationStack { // iOS 16+ 使用NavigationStack,低版本可替换为NavigationView
            ZStack {
                VStack {
                    HStack {
                        Text("Calendar View")
                            .bold()
                            .fontWeight(.heavy)
                            .font(.title)
                        Rectangle()
                            .foregroundColor(Color(hue: 0.032, saturation: 0.734, brightness: 0.973))
                            .frame(width: 65, height:20)
                            .shadow(radius: 7)
                            .cornerRadius(10)
                            .overlay {
                                Text("BETA")
                                    .font(.system(size:12))
                                    .padding()
                                    .foregroundColor(.white)
                                    .fontWeight(.heavy)
                            }
                        Spacer()
                        NavigationLink(destination: AddView()) {
                            Text("+")
                                .font(.system(size: 30)).fontWeight(.heavy)
                                .frame(width: 33, height: 25)
                                .foregroundColor(Color.white)
                                .padding(.bottom, 7)
                                .background(Color(hue: 0.032, saturation: 0.734, brightness: 0.973))
                                .cornerRadius(38.5)
                                .padding(.trailing, 15)
                        }
                    }
                    .padding(.leading, 20)
                    .padding(.top, 5)

                    HStack {
                        CalendarHelper(interval: DateInterval(start: .distantPast, end: .distantFuture), selectedDate: $selectedDate)
                    }
                }
            }
            // 选中日期后跳转详情页
            .navigationDestination(item: $selectedDate) { selectedDate in
                DetailView(targetDate: selectedDate)
            }
        }
    }
}

// 自定义详情视图示例
struct DetailView: View {
    let targetDate: Date
    
    var body: some View {
        VStack(spacing: 20) {
            Text("日期详情")
                .font(.title)
                .fontWeight(.bold)
            Text("选中日期:\(targetDate.formatted(date: .long, time: .omitted))")
                .font(.subheadline)
            // 可添加对应日期的CoreData数据展示逻辑
        }
        .padding()
    }
}

修改要点:

  • 添加@State private var selectedDate: Date?存储选中的日期
  • 给CalendarHelper传递selectedDate的绑定值
  • 使用navigationDestination实现选中日期后的跳转(低版本可替换为sheet或其他导航方式)
  • 示例了DetailView,可根据实际需求修改内容,比如添加对应日期的CoreData数据展示

内容的提问来源于stack exchange,提问作者user20715683

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 07:15:31