canvas绘制日历需日期计算与渲染严丝合缝:先按6行7列补全首尾空白,再通过坐标公式定位单元格,结合paint居中文字;状态用条件分支绘制,点击则坐标反推日期校验有效性。

Canvas绘制日历不是把日期“塞进控件”,而是把日历当成一张画布,用图形逻辑去表达时间关系。核心在于:日期计算决定“画什么”,Canvas渲染决定“怎么画”,二者必须严丝合缝——算错一天,坐标就偏移一格;画错位置,点击区域就失效。
日期计算:从当前月出发,铺满6行7列
标准月视图固定为6行×7列(最多42格),哪怕某月只有28天,也要补全首尾空白日。关键步骤是:
- 获取当月1号是星期几(
calendar.get(Calendar.DAY_OF_WEEK)),确定第一行从周几开始填 - 计算当月总天数(
calendar.getActualMaximum(Calendar.DAY_OF_MONTH)) - 向前补空:1号前的空白格数 = (星期几 - 1)% 7(注意:Android中星期日=1,星期一=2…)
- 向后补空:剩余格数 = 42 - 当月天数 - 前置空白数
坐标映射:把日期落到像素点上
每个格子不是自动布局,而是靠数学公式定位。假设画布宽width、高height,预留顶部星期栏高度weekHeight:
- 单元格宽度 =
width / 7,高度 =(height - weekHeight) / 6 - 第
r行第c列的左上角坐标:x = c * cellWidth,y = weekHeight + r * cellHeight - 文字居中需结合Paint的
ascent()和descent():垂直中心点 =y + cellHeight/2 - (paint.ascent() + paint.descent())/2
状态驱动绘制:不同日期,不同画法
不靠多个View切换状态,而靠条件分支复用同一段绘制逻辑:
- 当前月内日期 → 用深色字体绘制数字
- 非当前月日期 → 用浅灰、低透明度绘制
- 今天 → 加圆角背景或描边强调
- 有事件的日期 → 在右上角画小红点,或底部加进度弧线
- 选中日期 → 全格填充色+白色数字,避免仅改文字颜色导致对比度不足
交互响应:点击识别靠坐标反推日期
Canvas本身不提供点击事件,需手动转换:
- 监听
onTouchEvent,拿到触摸点(x, y) - 减去偏移(如星期栏高度),再整除单元格尺寸 → 得到行列索引
r, c - 根据前置空白数,算出该格对应的实际日期:
day = c - blankStart + 1 + r * 7 - 校验
day是否在当月有效范围内,再查数据源确认是否可交互











