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

material-calendarview添加日期事件标注问题求助

解决方案:为每个事件日期创建独立的DayViewDecorator

你的问题核心在于单个DayViewDecorator实例会被复用处理多个日期,用成员变量存储calendarDay会导致多日期装饰时的状态混乱,且框架调用顺序不符合预期。正确的做法是为每个有事件的日期创建独立的装饰器实例,直接在装饰器内部持有对应日期和事件信息。

步骤1:修改DayViewDecorator实现

创建一个带参数的装饰器类,在构造时传入目标日期和对应的事件,这样decorate方法可以直接使用已知的事件信息:

class EventDayDecorator(private val targetDay: CalendarDay, private val event: Event) : DayViewDecorator {
    override fun shouldDecorate(day: CalendarDay?): Boolean {
        // 只装饰目标日期
        return day == targetDay
    }

    override fun decorate(view: DayViewFacade?) {
        // 直接使用构造时传入的事件创建Span
        view?.addSpan(AddTextToDates(event.name))
    }
}

步骤2:批量添加装饰器到CalendarView

遍历你的mapOfCalendarDays,为每个有事件的日期创建对应装饰器并添加:

// 假设mapOfCalendarDays是<CalendarDay, Event>的映射
mapOfCalendarDays.forEach { (day, event) ->
    calendarView.addDecorator(EventDayDecorator(day, event))
}

步骤3:优化AddTextToDates Span(可选)

可以调整文本绘制的位置和样式,让效果更贴近目标需求:

class AddTextToDates(text: String) : LineBackgroundSpan {
    private val eventName = text
    // 自定义文本样式
    private val textPaint = Paint().apply {
        color = Color.BLACK
        textSize = 30f
        isAntiAlias = true
    }

    override fun drawBackground(
        canvas: Canvas,
        paint: Paint,
        left: Int,
        right: Int,
        top: Int,
        baseline: Int,
        bottom: Int,
        text: CharSequence,
        start: Int,
        end: Int,
        lnum: Int
    ) {
        // 让文本显示在日期下方居中
        val textX = (left + right) / 2f - textPaint.measureText(eventName) / 2f
        val textY = bottom + textPaint.textSize + 5f
        canvas.drawText(eventName, textX, textY, textPaint)
    }
}

替代方案:使用自定义DayView(复杂场景适用)

如果需要展示多个事件、自定义布局等复杂效果,可以直接自定义DayView:

  1. 继承MaterialCalendarView,重写onCreateDayView方法返回自定义DayView
  2. 在自定义DayView中根据当前日期加载事件并绘制

示例代码框架:

class CustomCalendarView(context: Context, attrs: AttributeSet) : MaterialCalendarView(context, attrs) {
    private var eventMap: Map<CalendarDay, Event>? = null

    fun setEventMap(map: Map<CalendarDay, Event>) {
        eventMap = map
        invalidate()
    }

    override fun onCreateDayView(parent: ViewGroup, day: CalendarDay): DayView {
        return CustomDayView(context, day, eventMap)
    }
}

class CustomDayView(context: Context, private val day: CalendarDay, private val eventMap: Map<CalendarDay, Event>?) : DayView(context) {
    private val textPaint = Paint().apply {
        color = Color.BLACK
        textSize = 30f
        isAntiAlias = true
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        // 绘制日期后,再绘制事件文本
        eventMap?.get(day)?.let { event ->
            val textX = width / 2f - textPaint.measureText(event.name) / 2f
            val textY = height + textPaint.textSize + 5f
            canvas.drawText(event.name, textX, textY, textPaint)
        }
    }
}

这种方式能更灵活地控制每个日期的展示内容,适合需求复杂的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 10:45:19