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

SwiftUI日历isToday函数失效:切换年份后当前日期高亮消失

问题分析与解决方案

问题根源

你的日历切换年份后切回当前年份时高亮消失,核心原因是**ForEach使用day本身作为唯一标识**。当跨年份切换时,同一个日期数字(比如5号)会被SwiftUI视为同一个视图并复用,导致isToday的计算结果没有重新触发,高亮状态未更新。

另外,currentDay、currentMonth、currentYear被定义为private let,只会在视图初始化时获取一次,若App运行超过一天,这些值也不会自动更新,属于潜在问题。


修复步骤

1. 替换ForEach的唯一标识

将每个日期的标识改为年份-月份-日期的组合,确保每个日期的ID全局唯一,避免SwiftUI复用视图:

修改原代码中日期列表的ForEach部分:

// 原代码
ForEach(getDaysInMonth(month: month, year: year), id: \.self) { day in

// 修改后
ForEach(getDaysInMonth(month: month, year: year), id: { "\(year)-\(month)-\($0)" }) { day in

2. 优化当前日期的获取方式

将currentDay、currentMonth、currentYear改为计算属性,每次调用时实时获取当前日期,避免初始化后固定不变:

替换原代码中的三个private let:

// 原代码
private let currentDay = Calendar.current.component(.day, from: Date())
private let currentMonth = Calendar.current.component(.month, from: Date())
private let currentYear = Calendar.current.component(.year, from: Date())

// 修改后
private var currentDay: Int { Calendar.current.component(.day, from: Date()) }
private var currentMonth: Int { Calendar.current.component(.month, from: Date()) }
private var currentYear: Int { Calendar.current.component(.year, from: Date()) }

3. 可选:优化isToday函数(增强健壮性)

直接对比Date对象而非单独的年月日组件,避免因日历设置不同导致的匹配错误:

func isToday(day: Int, month: Int, year: Int) -> Bool {
    guard let date = Calendar.current.date(from: DateComponents(year: year, month: month, day: day)) else {
        return false
    }
    return Calendar.current.isDateInToday(date)
}

完整修复后的核心代码片段

struct MonthOverviewView: View {
    @State private var year: Int = Calendar.current.component(.year, from: Date())
    @State private var scrollProxy: ScrollViewProxy? = nil
    @State private var hasScrolledToToday = false
    private let calendar = Calendar.current
    private let daysOfWeek = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
    
    // 改为计算属性,实时获取当前日期
    private var currentDay: Int { Calendar.current.component(.day, from: Date()) }
    private var currentMonth: Int { Calendar.current.component(.month, from: Date()) }
    private var currentYear: Int { Calendar.current.component(.year, from: Date()) }

    var body: some View {
        VStack {
            // ... 导航栏代码保持不变 ...
            
            ScrollViewReader { proxy in
                ScrollView { 
                    VStack(spacing: 40) {
                        ForEach(1...12, id: \.self) { month in
                            VStack {
                                // ... 月份标题、星期栏代码保持不变 ...
                                
                                LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 7), spacing: 20) {
                                    // 修改ForEach的id为唯一日期标识
                                    ForEach(getDaysInMonth(month: month, year: year), id: { "\(year)-\(month)-\($0)" }) { day in
                                        if day != 0 {
                                            VStack(alignment: .leading) {
                                                Text("\(day)")
                                                    .font(.body)
                                                    .bold()
                                                    .foregroundColor(isToday(day: day, month: month, year: year) ? .red : .black)
                                                    .padding(.bottom, 10)
                                                    .padding(.leading, 5)
                                                
                                                Rectangle()
                                                    .fill(Color.clear)
                                                    .frame(height: 60)
                                            }
                                            .frame(minHeight: 120)
                                            .border(Color.gray.opacity(0.2), width: 1)
                                            .id("day-\(day)-\(month)")
                                        } else {
                                            Color.clear
                                        }
                                    }
                                }
                                .padding(.horizontal)
                            }
                        }
                    }
                    .onAppear {
                        // ... onAppear代码保持不变 ...
                    }
                }
            }
        }
    }
    
    // ... getDaysInMonth函数保持不变 ...
    
    // 优化后的isToday函数
    func isToday(day: Int, month: Int, year: Int) -> Bool {
        guard let date = Calendar.current.date(from: DateComponents(year: year, month: month, day: day)) else {
            return false
        }
        return Calendar.current.isDateInToday(date)
    }
}

效果验证

修改后,切换到任意年份再切回当前年份,今日的红色高亮会正常显示;即使App运行多天,当前日期的高亮也会自动更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 21:44:52