-
Calendar的绘制由CalendarRenderer完成,IDayRenderer实现自定义的日期效果,CalendarAttr中存储日历的属性。
-
首先看一下Calendar的代码,Calendar主要是初始化Renderer和Attr,然后接受View的生命周期
-
在OnDraw的时候调用Renderer的onDraw方法,在点击事件onTouchEvent触发时,调用Renderer的点击处理逻辑
private void initAttrAndRenderer() {
calendarAttr = new CalendarAttr();
calendarAttr.setWeekArrayType(CalendarAttr.WeekArrayType.Monday);
calendarAttr.setCalendarType(CalendarAttr.CalendayType.MONTH);
renderer = new CalendarRenderer(this , calendarAttr , context);
renderer.setOnSelectDateListener(onSelectDateListener);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
renderer.draw(canvas);
}
private float posX = 0;
private float posY = 0;
/*
- 触摸事件为了确定点击的位置日期
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
posX = event.getX();
posY = event.getY();
break;
case MotionEvent.ACTION_UP:
float disX = event.getX() - posX;
float disY = event.getY() - posY;
if (Math.abs(disX) < touchSlop && Math.abs(disY) < touchSlop) {
int col = (int) (posX / cellWidth);
int row = (int) (posY / cellHeight);
onAdapterSelectListener.cancelSelectState();
renderer.onClickDate(col, row);
onAdapterSelectListener.updateSelectState();
invalidate();
}
break;
}
return true;
}
- 然后看一下CalendarRenderer的代码,Renderer承担了Calendar的绘制任务,首先renderer根据种子日期seedDate填充出Calendar包含的Date数据,calendar中持有一个6*7二维数组来存放日期数据。然后在onDraw的时候通过IDayRenderer来完成对日历的绘制。当点击日期改变了日期的状态时,首先改变对应日期的状态State,然后重绘Calendar。
private void instantiateMonth() {
int lastMonthDays = Utils.getMonthDays(seedDate.year, seedDate.month - 1); // 上个月的天数
int currentMonthDays = Utils.getMonthDays(seedDate.year, seedDate.month); // 当前月的天数
int firstDayPosition = Utils.getFirstDayWeekPosition(seedDate.year, seedDate.month , CalendarViewAdapter.weekArrayType);
int day = 0;
for (int row = 0; row < Const.TOTAL_ROW; row++) {
day = fillWeek(lastMonthDays, currentMonthDays, firstDayPosition, day, row);
}
}
private int fillWeek(int lastMonthDays, int currentMonthDays, int firstDayWeek, int day, int row) {
for (int col = 0; col < Const.TOTAL_COL; col++) {
int position = col + row * Const.TOTAL_COL; // 单元格位置
if (position >= firstDayWeek && position < firstDayWeek + currentMonthDays) { // 本月的
day ++;
fillCurrentMonthDate(day, row, col);
} else if (position < firstDayWeek) { //last month
instantiateLastMonth(lastMonthDays, firstDayWeek, row, col, position);
} else if (position >= firstDayWeek + currentMonthDays) {//next month
instantiateNextMonth(currentMonthDays, firstDayWeek, row, col, position);
}
}
return day;
}
public void draw(Canvas canvas) {
for (int row = 0; row < Const.TOTAL_ROW; row++) {
if (weeks[row] != null) {
for (int col = 0; col < Const.TOTAL_COL; col ++) {
if (weeks[row].days[col] != null) {
dayRenderer.drawDay(canvas , weeks[row].days[col]);
}
}
}
}
}
public void onClickDate(int col, int row) {
if (col >= Const.TOTAL_COL || row >= Const.TOTAL_ROW)
return;
if (weeks[row] != null) {
if(attr.getCalendarType() == CalendarAttr.CalendayType.MONTH) {
if(weeks[row].days[col].getState() == State.CURRE