可能是第十好的Android 开源 日历 Calendar 仿小米

本文介绍了Android平台一个开源的日历组件实现,详细讲解了其内部逻辑,包括日历的渲染、日期点击事件处理、以及在周月模式间的切换。通过对CalendarRenderer和IDayRenderer的使用,展示了如何自定义日期效果和实现日历的绘制。此外,还提到了使用RecyclerViewBehavior和MonthPagerBehavior实现周月切换时的交互效果。
摘要由CSDN通过智能技术生成

思路


  • 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

  • 24
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值