Android Kotlin 如何通过代码动态修改CalendarView指定日期的文本颜色
Android Kotlin 动态修改CalendarView指定日期文本颜色实现方案
前置说明
原生CalendarView存在两个限制,是你之前尝试失效的原因:
dateTextAppearance属性接收的是样式资源ID,并非直接的颜色值,你打印得到的16974789是系统默认样式的资源ID,不是色值,所以转换后和实际显示效果不符- 该属性是全局生效配置,没有公开API支持直接修改单个指定日期的文本样式
可行实现方案
方案1:自定义View继承原生CalendarView重写绘制逻辑(无第三方依赖)
核心思路是重写onDraw方法,遍历当前可见的所有日期,和你数据库存储的标记日期匹配,匹配成功的日期单独修改画笔颜色绘制文本:
class MarkableCalendarView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : CalendarView(context, attrs, defStyleAttr) { // 存储需要标记的日期和对应颜色,key为日期毫秒值,value为标记色 val markDateMap = hashMapOf<Long, Int>() private val tempCalendar = Calendar.getInstance() private val textPaint = Paint().apply { isAntiAlias = true textAlign = Paint.Align.CENTER } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) // 遍历当前月份所有可见日期 val firstDay = firstVisibleDay val lastDay = lastVisibleDay tempCalendar.timeInMillis = firstDay while (tempCalendar.timeInMillis <= lastDay) { val currentTime = tempCalendar.timeInMillis // 匹配到标记日期就修改颜色绘制 if (markDateMap.containsKey(currentTime)) { val dayOfMonth = tempCalendar.get(Calendar.DAY_OF_MONTH) val position = getPositionForDay(dayOfMonth) textPaint.color = markDateMap[currentTime]!! textPaint.textSize = 48f // 可自定义字体大小 canvas.drawText(dayOfMonth.toString(), position.x, position.y, textPaint) } tempCalendar.add(Calendar.DAY_OF_MONTH, 1) } } // 坐标计算方法,需根据你实际控件的宽高、列数、padding调整参数 private fun getPositionForDay(dayOfMonth: Int): Point { val columnCount = 7 // 每周7天 val rowCount = 6 // 月视图最多6行 val cellWidth = (width - paddingLeft - paddingRight) / columnCount val cellHeight = (height - paddingTop - paddingBottom) / rowCount val firstDayOfWeek = firstDayOfWeek val offset = (dayOfMonth + firstDayOfWeek - 2) % 7 val row = (dayOfMonth + firstDayOfWeek - 2) / 7 val x = paddingLeft + offset * cellWidth + cellWidth / 2 val y = paddingTop + row * cellHeight + cellHeight / 2 - (textPaint.descent() + textPaint.ascent()) / 2 return Point(x, y.toInt()) } }
使用时直接从数据库读取标记数据更新map即可:
val calendarView = findViewById<MarkableCalendarView>(R.id.next_month_calendar_view) // 从数据库读取所有标记为true的日期存入map database.markedDates.forEach { dateEntity -> if (dateEntity.isMarked) { calendarView.markDateMap[dateEntity.dateTime] = Color.RED // 自定义标记颜色 } } calendarView.invalidate() // 触发重绘更新UI
方案2:使用封装好的第三方日历控件(实现更简单,适配性更强)
如果不想自己处理绘制逻辑,可以使用成熟的第三方日历控件,内置了装饰器功能,直接配置对应日期的颜色即可,核心使用逻辑如下:
// 初始化日历控件后,添加自定义装饰器 calendarView.addDecorator(object : DayViewDecorator { override fun shouldDecorate(day: CalendarDay): Boolean { // 匹配数据库中标记为true的日期 return database.markedDates.any { it.dateTime == day.date.time && it.isMarked } } override fun decorate(view: DayViewFacade) { view.setTextColor(Color.RED) // 直接设置标记日期的文本颜色 } })
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

