可能是第十好的Android 开源 日历 Calendar 仿小米,作为移动开发程序员

可能是第十好的Android 开源 日历 Calendar 仿小米,作为移动开发程序员,第1张

可能是第十好的Android 开源 日历 Calendar 仿小米,作为移动开发程序员

CalendarViewAdapter.saveDate(selectedDate);

onSelectDateListener.onSelectDate(selectedDate);

seedDate = selectedDate;

} else if (weeks[row].days[col].getState() == State.PAST_MONTH){

selectedDate = weeks[row].days[col].getDate();

CalendarViewAdapter.saveDate(selectedDate);

onSelectDateListener.onSelectOtherMonth(-1);

onSelectDateListener.onSelectDate(selectedDate);

} else if (weeks[row].days[col].getState() == State.NEXT_MONTH){

selectedDate = weeks[row].days[col].getDate();

CalendarViewAdapter.saveDate(selectedDate);

onSelectDateListener.onSelectOtherMonth(1);

onSelectDateListener.onSelectDate(selectedDate);

}

} else {

weeks[row].days[col].setState(State.SELECT);

selectedDate = weeks[row].days[col].getDate();

CalendarViewAdapter.saveDate(selectedDate);

onSelectDateListener.onSelectDate(selectedDate);

seedDate = selectedDate;

}

}

}

  • 调用Renderer的draw方法时使用dayRenderer.drawDay(canvas , weeks[row].days[col]),dayRenderer是一个接口,在lib中有一个DayView 的抽象类实现该接口。 其中的drawDay方法完成了对该天到calendar的canvas上的绘制

@Override

public void drawDay(Canvas canvas , Day day) {

this.day = day;

refreshContent();

int saveId = canvas.save();

canvas.translate(day.getPosCol() * getMeasuredWidth(),

day.getPosRow() * getMeasuredHeight());

draw(canvas);

canvas.restoreToCount(saveId);

}

  • 使用继承自ViewPager的MonthPager来存放calendar的view

viewPageChangeListener = new ViewPager.onPageChangeListener() {}

//新建viewPagerChangeListener

@Override

protected void onSizeChanged(int w, int h, int oldW, int oldH) {

cellHeight = h / 6;

super.onSizeChanged(w, h, oldW, oldH);

}//重写onSizeChanged,获取dayView的高度

public int getTopMovableDistance() {

CalendarViewAdapter calendarViewAdapter = (CalendarViewAdapter) getAdapter();

rowIndex = calendarViewAdapter.getPagers().get(currentPosition % 3).getSelectedRowIndex();

return cellHeight * rowIndex;

}//计算周月切换时在到达选中行之前MonthPager收起的距离

public int getRowIndex() {

CalendarViewAdapter calendarViewAdapter = (CalendarViewAdapter) getAdapter();

rowIndex = calendarViewAdapter.getPagers().get(currentPosition % 3).getSelectedRowIndex();

Log.e(“ldf”,"getRowIndex = " + rowIndex);

return rowIndex;

}//计算选中日期所在的行数

  • 使用CalendarViewAdapter为MonthPager填充calendar的实例

@Override

public void setPrimaryItem(ViewGroup container, int position, Object object) {

super.setPrimaryItem(container, position, object);

this.currentPosition = position;

}

@Override

public Object instantiateItem(ViewGroup container, int position) {

if(position < 2){

return null;

}

Calendar calendar = calendars.get(position % calendars.size());

if(calendarType == CalendarAttr.CalendayType.MONTH) {

CalendarDate current = seedDate.modifyMonth(position - MonthPager.CURRENT_DAY_INDEX);

current.setDay(1);//每月的种子日期都是1号

calendar.showDate(current);

} else {

CalendarDate current = seedDate.modifyWeek(position - MonthPager.CURRENT_DAY_INDEX);

if(weekArrayType == 1) {

calendar.showDate(Utils.getSaturday(current));

} else {

calendar.showDate(Utils.getSunday(current));

}//每周的种子日期为这一周的最后一天

calendar.updateWeek(rowCount);

}

if (container.getChildCount() == calendars.size()) {

container.removeView(calendars.get(position % 3));

}

if(container.getChildCount() < calendars.size()) {

container.addView(calendar, 0);

} else {

container.addView(calendar, position % 3);

}

return calendar;

}

  • 日历在切换周月时切换日历中填充的数据

  • 在月模式切换成周模式时,将当前页的seedDate拿出来刷新本页数据,并且更新指定行数的周数据,然后得到seedDate下一周的周日作为下一页的seedDate,刷新下一页的数据,并且更新指定行数的周数据。上一页同理

  • 也是说假设我当前选择的是6月12号周日,处于日历的第二行,也是说下一页的seedDate是6月19号,然后刷新6月19号所在周的数据到选定的第二行。

  • 当切换周月时,把三页的数据都会重新刷新一遍,以保证数据的正确性。

public void switchToMonth() {

if(calendars != null && calendars.size() > 0 && calendarType != CalendarAttr.CalendayType.MONTH){

calendarType = CalendarAttr.CalendayType.MONTH;

MonthPager.CURRENT_DAY_INDEX = currentPosition;

Calendar v = calendars.get(currentPosition % 3);//0

seedDate = v.getSeedDate();

Calendar v1 = calendars.get(currentPosition % 3);//0

v1.switchCalendarType(CalendarAttr.CalendayType.MONTH);

v1.showDate(seedDate);

Calendar v2 = calendars.get((currentPosition - 1) % 3);//2

v2.switchCalendarType(CalendarAttr.CalendayType.MONTH);

CalendarDate last = seedDate.modifyMonth(-1);

last.setDay(1);

v2.showDate(last);

Calendar v3 = calendars.get((currentPosition + 1) % 3);//1

v3.switchCalendarType(CalendarAttr.CalendayType.MONTH);

CalendarDate next = seedDate.modifyMonth(1);

next.setDay(1);

v3.showDate(next);

}

}

public void switchToWeek(int rowIndex) {

rowCount = rowIndex;

if(calendars != null && calendars.size() > 0 && calendarType != CalendarAttr.CalendayType.WEEK){

calendarType = CalendarAttr.CalendayType.WEEK;

MonthPager.CURRENT_DAY_INDEX = currentPosition;

Calendar v = calendars.get(currentPosition % 3);

seedDate = v.getSeedDate();

rowCount = v.getSelectedRowIndex();

Calendar v1 = calendars.get(currentPosition % 3);

v1.switchCalendarType(CalendarAttr.CalendayType.WEEK);

v1.showDate(seedDate);

v1.updateWeek(rowIndex);

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

Calendar v2 = calendars.get((currentPosition - 1) % 3);

v2.switchCalendarType(CalendarAttr.CalendayType.WEEK);

CalendarDate last = seedDate.modifyWeek(-1);

if(weekArrayType == 1) {

v2.showDate(Utils.getSaturday(last));

} else {

v2.showDate(Utils.getSunday(last));

}//每周的种子日期为这一周的最后一天

v2.updateWeek(rowIndex);

Calendar v3 = calendars.get((currentPosition + 1) % 3);

v3.switchCalendarType(CalendarAttr.CalendayType.WEEK);

CalendarDate next = seedDate.modifyWeek(1);

if(weekArrayType == 1) {

v3.showDate(Utils.getSaturday(next));

} else {

v3.showDate(Utils.getSunday(next));

}//每周的种子日期为这一周的最后一天

v3.updateWeek(rowIndex);

}

}

  • 使用CoordinateLayout的特性来做周月模式切换

  • 1.RecyclerViewBehavior

@Override

public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, RecyclerView child,

View directTargetChild, View target, int nestedScrollAxes) {

LinearLayoutManager linearLayoutManager = (LinearLayoutManager) child.getLayoutManager();

if(linearLayoutManager.findFirstCompletelyVisibleItemPosition() > 0) {

return false;

}

boolean isVertical = (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;

int firstRowVerticalPosition =

(child == null || child.getChildCount() == 0) ? 0 : child.getChildAt(0).getTop();

boolean recycleviewTopStatus = firstRowVerticalPosition >= 0;

return isVertical && (recycleviewTopStatus || !Utils.isScrollToBottom()) && child == directTargetChild;

}

@Override

public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, RecyclerView child,

View target, int dx, int dy, int[] consumed) {

super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);

if (child.getTop() <= initOffset && child.getTop() >= minOffset) {

consumed[1] = Utils.scroll(child, dy, minOffset, initOffset);

saveTop(child.getTop());

}

}

@Override

public void onStopNestedScroll(final CoordinatorLayout parent, final RecyclerView child, View target) {

Log.e(“ldf”,“onStopNestedScroll”);

super.onStopNestedScroll(parent, child, target);

if (!Utils.isScrollToBottom()) {

if (initOffset - Utils.loadTop() > Utils.getTouchSlop(context)){

scrollTo(parent, child, minOffset, 200);

} else {

scrollTo(parent, child, initOffset, 80);

}

} else {

if (Utils.loadTop() - minOffset > Utils.getTouchSlop(context)){

scrollTo(parent, child, initOffset, 200);

} else {

scrollTo(parent, child, minOffset, 80);

}

}

}

  • (2)MonthPagerBehavior 当recyclerView滑动式,MonthPager做相应的变化。

@Override

public boolean onDependentViewChanged(CoordinatorLayout parent, MonthPager child, View dependency) {

Log.e(“ldf”,“onDependentViewChanged”);

CalendarViewAdapter calendarViewAdapter = (CalendarViewAdapter) child.getAdapter();

if (dependentViewTop != -1) {

int dy = dependency.getTop() - dependentViewTop; //dependency对其依赖的view(本例依赖的view是RecycleView)

int top = child.getTop();

if( dy > touchSlop){

calendarViewAdapter.switchToMonth();

} else if(dy < - touchSlop){

calendarViewAdapter.switchToWeek(child.getRowIndex());

}

if (dy > -top){

dy = -top;

}

if (dy < -top - child.getTopMovableDistance()){

dy = -top - child.getTopMovableDistance();

}

child.offsetTopAndBottom(dy);

} else {

initRecyclerViewTop = dependency.getTop();

}

dependentViewTop = dependency.getTop();

top = child.getTop();

if((initRecyclerViewTop - dependentViewTop) >= child.getCellHeight()) {

Utils.setScrollToBottom(false);

calendarViewAdapter.switchToWeek(child.getRowIndex());

initRecyclerViewTop = dependentViewTop;

}

if((dependentViewTop - initRecyclerViewTop) >= child.getCellHeight()) {

Utils.setScrollToBottom(true);

calendarViewAdapter.switchToMonth();

initRecyclerViewTop = dependentViewTop;

}

return true;

// TODO: 16/12/8 dy为负时表示向上滑动,dy为正时表示向下滑动,dy为零时表示滑动停止

}

  • 使用IDayRender来实现自定义的日历效果

DayView实现IDayRenderer,我们新建一个CustomDayView继承自DayView,在里面作自定义的显示

public CustomDayView(Context context, int layoutResource) {

super(context, layoutResource);

dateTv = (TextView) findViewById(R.id.date);

marker = (ImageView) findViewById(R.id.maker);

selectedBackground = findViewById(R.id.selected_background);

todayBackground = findViewById(R.id.today_background);

}

@Override

public void refreshContent() {

renderToday(day.getDate());

renderSelect(day.getState());

renderMarker(day.getDate(), day.getState());

super.refreshContent();

}

使用方法


XML布局
  • 新建XML布局

RecyclerView的layout_behavior为com.ldf.calendar.behavior.RecyclerViewBehavior

android:id="@+id/content"

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:layout_weight=“1”>

android:id="@+id/calendar_view"

android:layout_width=“match_parent”

android:layout_height=“300dp”

android:background="#fff">

android:id="@+id/list"

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

app:layout_behavior=“com.ldf.calendar.behavior.RecyclerViewBehavior”

android:background="#c2c2c2"

android:layout_gravity=“bottom”/>

自定义日历样式
  • 新建CustomDayView继承自DayView并重写refreshContent 和 copy 两个方法

@Override

public void refreshContent() {

//你的代码 你可以在这里定义你的显示规则

super.refreshContent();

}

@Override

public IDayRenderer copy() {

return new CustomDayView(context , layoutResource);

}

  • 新建CustomDayView实例,并作为参数构建CalendarViewAdapter

CustomDayView customDayView = new CustomDayView(

context , R.layout.custom_day);

calendarAdapter = new CalendarViewAdapter(

context ,

onSelectDateListener ,

Calendar.MONTH_TYPE ,

customDayView);

初始化View
  • 目前来看 相比于Dialog选择日历 我的控件更适合于Activity/Fragment在Activity的onCreate 或者Fragment的onCreateView 你需要实现这两个方法来启动日历并装填进数据

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_syllabus);

initCalendarView();

}

private void initCalendarView() {

initListener();

CustomDayView customDayView = new CustomDayView(

context , R.layout.custom_day);

calendarAdapter = new CalendarViewAdapter(

context ,

onSelectDateListener ,

Calendar.MONTH_TYPE ,

customDayView);

initMarkData();

initMonthPager();

}

使用此方法回调日历点击事件

private void initListener() {

onSelectDateListener = new onSelectDateListener() {

@Override

public void onSelectDate(CalendarDate date) {

//your code

}

@Override

public void onSelectOtherMonth(int offset) {

//偏移量 -1表示上一个月 , 1表示下一个月

monthPager.selectOtherMonth(offset);

}

};

}

使用此方法初始化日历标记数据

private void initMarkData() {

HashMap markData = new HashMap<>();

//1表示红点,0表示灰点

markData.put(“2017-8-9” , “1”);

markData.put(“2017-7-9” , “0”);

markData.put(“2017-6-9” , “1”);

markData.put(“2017-6-10” , “0”);

calendarAdapter.setMarkData(markData);

}

使用此方法给MonthPager添加上相关监听

monthPager.addonPageChangeListener(new MonthPager.onPageChangeListener() {

@Override

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

}

@Override

public void onPageSelected(int position) {

mCurrentPage = position;

currentCalendars = calendarAdapter.getAllItems();

if(currentCalendars.get(position % currentCalendars.size()) instanceof Calendar){

//you code

}

}

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/zaji/5660993.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-12-16
下一篇2022-12-16

发表评论

登录后才能评论

评论列表(0条)

    保存