基于kizitonwose Calendar的自定义CalendarView更新异常排查
解决Room事件加载到kizitonwose日历视图的图标显示问题
错误原因
当前实现存在两个核心问题:
- 使用全局变量
eventEventType存储事件类型,遍历事件时该变量会被最后一个事件覆盖,导致所有有事件的日期都显示最后一个事件的图标。 - 事件加载逻辑错误:遍历事件时调用
viewModel.deleteEvent会删除刚读取的事件,且未正确将日期与事件类型关联存储。
修复步骤与代码修改
1. 定义事件存储结构
在Fragment中声明一个Map,用于存储日期-事件类型的对应关系:
private val events = mutableMapOf<LocalDate, String>()
2. 修正Room事件加载逻辑
替换onViewCreated中的事件遍历代码,将事件存入Map而非删除:
// 原for循环替换为以下代码 viewModel.allEvents.forEach { item -> val currentDate = item.date val currentIssueType = item.eventType println("currentIssueType eventType ------------> $currentIssueType") // 将事件关联到对应日期 events[currentDate] = currentIssueType } // 通知日历刷新视图 binding.viewCalendar.notifyCalendarChanged()
3. 修正日历DayBinder绑定逻辑
修改configureBinders中的bind方法,根据当前日期从Map中获取对应事件类型:
override fun bind(container: DayViewContainer, data: CalendarDay) { container.day = data val textView = container.binding.calendarDayText val dotView = container.binding.exThreeDotView textView.text = data.date.dayOfMonth.toString() if (data.position == DayPosition.MonthDate) { textView.makeVisible() when (data.date) { today -> { textView.setTextColorRes(R.color.example_3_white) textView.setBackgroundResource(R.drawable.day_today_bg) dotView.makeInVisible() } selectedDate -> { textView.setTextColorRes(R.color.colorPrimaryDark) textView.setBackgroundResource(R.drawable.day_selected_bg) dotView.makeInVisible() } else -> { // 获取当前日期对应的事件类型 val eventType = events[data.date] // 根据事件类型设置图标 eventType?.let { type -> when (type) { "Light" -> dotView.setImageResource(R.drawable.day_light_bg) "Medium" -> dotView.setImageResource(R.drawable.day_medium_bg) "Heavy" -> dotView.setImageResource(R.drawable.day_heavy_bg) "Spotting" -> { dotView.scaleType = ImageView.ScaleType.CENTER_INSIDE dotView.setImageResource(R.drawable.day_spotting_bg) } "Start" -> dotView.setImageResource(R.drawable.day_start_bg) "Future" -> dotView.setImageResource(R.drawable.day_future_bg) } dotView.makeVisible() } ?: dotView.makeInVisible() // 无事件则隐藏图标 textView.setTextColorRes(R.color.example_3_black) textView.background = null } } } else { textView.makeInVisible() dotView.makeInVisible() } }
Room事件加载优化建议
- 用LiveData监听数据变化:将ViewModel中的事件列表改为LiveData,实现数据库更新时日历自动刷新:
// ViewModel内 val allEventsLiveData: LiveData<List<Event>> = eventDao.getAllEvents() // Fragment内 viewModel.allEventsLiveData.observe(viewLifecycleOwner) { eventList -> events.clear() eventList.forEach { events[it.date] = it.eventType } binding.viewCalendar.notifyCalendarChanged() } - 移除错误的删除操作:删除
viewModel.deleteEvent调用,避免丢失Room中的事件数据。 - 统一日期类型:确保Room实体类中日期字段使用
LocalDate(配合Room的TypeConverter),与日历组件的日期类型保持一致,避免转换错误。
内容的提问来源于stack exchange,提问作者Brian Richey
相关产品推荐
相关产品推荐

