CalendarView學(xué)習(xí)使用挖坑填坑秘籍

github地址:https://github.com/huanghaibin-dev/CalendarView

推薦一篇講解CalendarView特別好的博客:https://blog.csdn.net/huanghaibin_dev/article/details/79040147

我的這篇文章重點不是講解CalendarView怎么使用的,是說我在使用過程中,由于自己腦抽,本來很容易的事情,被自己搞復(fù)雜了。尤其是下文第3點,到現(xiàn)在都懷疑當(dāng)時的自己怎么看資料的。怎么修改“時間選擇范圍”背景色、結(jié)束日期小于開始日期依舊繪制及處理邏輯、根據(jù)項目需求實時顯示當(dāng)前年月……,以達到UI效果

一:基本屬性的使用:

1.日歷顯示模式有三種(由CalendarLayout控制,直接在布局里面設(shè)置,eg:app:calendar_show_mode="both_month_week_view ",):

both_month_week_view //月模式和周模式(默認模式,可切換月周模式)

only_week_view //周模式

only_month_view //月模式

2.設(shè)置日歷間距calendarView.setCalendarItemHeight

3.想要日歷月周模式切換時,下面(指日歷下面的布局)的內(nèi)容跟著上下走動。這個梗,一開始接觸這個日歷時,研究了好久,一直沒有做出來,主要是:

1)沒有設(shè)置calendar_show_mode屬性為both_month_week_view;

2)一直誤認為com.haibin.calendarviewproject.group.GroupRecyclerView才是真正實現(xiàn),下面跟隨日歷上下收縮的關(guān)鍵。其實項目的要求是,日歷下面跟隨著一個Webview,這個Webview跟隨日歷收縮而進行上下。到了某天,突然間理解了

以WebView為例,重點是:

(1)在CalendarLayout設(shè)置app:calendar_content_view_id="@+id/recyclerView"這個屬性,recyclerView就是WebView的id;

(2)WebView必須在CalendarView后面:


<com.haibin.calendarview.CalendarLayout? ? android:id="@+id/calendarLayout"? ? android:layout_width="match_parent"? ? android:layout_height="match_parent"? ? android:orientation="vertical"? ? app:calendar_show_mode="both_month_week_view "? ? app:default_status="shrink"? ? app:calendar_content_view_id="@+id/recyclerView">? ? <com.haibin.calendarview.CalendarView? ? ? ? android:id="@+id/calendarView"? ? ? ? …………? ? ? />

<!--會跟隨日歷月周模式切換,而進行上下走動(也許描述不太好,就是一直跟在日歷后面,無論是周還是月模式),這個WebView可以替換成任何控件-->

? ? <WebView

? ? ? ? android:id="@+id/recyclerView"

? ? ? ? …………

? ? ? />

</com.haibin.calendarview.CalendarLayout>

4.回到今天:CalendarView.scrollToCurrent()

5.修改選擇范圍背景色,如下圖所示:

CustomRangeMonthView.java(CustomRangeWeekView.java同理)代碼改成如下:

? private int mRadius;

? ? private int middleColor = CalendarColors.middleColor;//中間范圍背景色

? ? private int selectedColor = CalendarColors.selectedColor;//選擇的背景色

? ? private int middleTxtColor = CalendarColors.middleTxtColor;//中間范圍字體顏色

? ? private int selectedTxtColor = CalendarColors.selectedTxtColor;//選擇字體顏色

? ? public CustomRangeMonthView(Context context) {

? ? ? ? super(context);

? ? }

? ? @Override

? ? protected void onPreviewHook() {

? ? ? ? mRadius = Math.min(mItemWidth, mItemHeight) / 5 * 2;

? ? ? ? mSchemePaint.setStyle(Paint.Style.STROKE);

? ? }

? ? /**

? ? * 繪制選中的日期

? ? *

? ? * @param canvas? ? ? ? canvas

? ? * @param calendar? ? ? 日歷日歷calendar

? ? * @param x? ? ? ? ? ? ? 日歷Card x起點坐標(biāo)

? ? * @param y? ? ? ? ? ? ? 日歷Card y起點坐標(biāo)

? ? * @param hasScheme? ? ? hasScheme 非標(biāo)記的日期

? ? * @param isSelectedPre? 上一個日期是否選中

? ? * @param isSelectedNext 下一個日期是否選中

? ? * @return 是否繼續(xù)繪制onDrawScheme,true or false

? ? */

? ? @Override

? ? protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? boolean isSelectedPre, boolean isSelectedNext) {

? ? ? ? int cx = x + mItemWidth / 2;

? ? ? ? int cy = y + mItemHeight / 2;

? ? ? ? if (isSelectedPre) {

? ? ? ? ? ? if (isSelectedNext) {// 中間日期

? ? ? ? ? ? ? ? mSelectedPaint.setColor(middleColor);

? ? ? ? ? ? ? ? canvas.drawRect(x, cy - mRadius, x + mItemWidth, cy + mRadius, mSelectedPaint);

? ? ? ? ? ? } else {//最后一個,the last 最后一個日期

? ? ? ? ? ? ? ? mSelectedPaint.setColor(middleColor);

? ? ? ? ? ? ? ? canvas.drawRect(x, cy - mRadius, cx, cy + mRadius, mSelectedPaint);

? ? ? ? ? ? ? ? mSelectedPaint.setColor(selectedColor);

? ? ? ? ? ? ? ? canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);

? ? ? ? ? ? }

? ? ? ? } else {

? ? ? ? ? ? if(isSelectedNext){

? ? ? ? ? ? ? ? mSelectedPaint.setColor(middleColor);

? ? ? ? ? ? ? ? canvas.drawRect(cx, cy - mRadius, x + mItemWidth, cy + mRadius, mSelectedPaint);

? ? ? ? ? ? }

? ? ? ? ? ? mSelectedPaint.setColor(selectedColor);

? ? ? ? ? ? canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);

? ? ? ? }

? ? ? ? return false;

? ? }

? ? @Override

? ? protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y, boolean isSelected) {

? ? ? ? int cx = x + mItemWidth / 2;

? ? ? ? int cy = y + mItemHeight / 2;

? ? ? ? canvas.drawCircle(cx, cy, mRadius, mSchemePaint);

? ? }

? ? @Override

? ? protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {

? ? ? ? float baselineY = mTextBaseLine + y;

? ? ? ? int cx = x + mItemWidth / 2;

? ? ? ? boolean isInRange = isInRange(calendar);

? ? ? ? boolean isEnable = !onCalendarIntercept(calendar);

? ? ? ? if (isSelected) {

? ? ? ? ? ? boolean isSelectedPre = isSelectPreCalendar(calendar);

? ? ? ? ? ? boolean isSelectedNext = isSelectNextCalendar(calendar);

? ? ? ? ? ? if (isSelectedPre) {

? ? ? ? ? ? ? ? if (isSelectedNext) {// 中間日期

? ? ? ? ? ? ? ? ? ? mSelectTextPaint.setColor(middleTxtColor);

? ? ? ? ? ? ? ? } else {//最后一個,the last 最后一個日期

? ? ? ? ? ? ? ? ? ? mSelectTextPaint.setColor(selectedTxtColor);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? if(isSelectedNext){

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? mSelectTextPaint.setColor(selectedTxtColor);

? ? ? ? ? ? }

? ? ? ? ? ? canvas.drawText(String.valueOf(calendar.getDay()),

? ? ? ? ? ? ? ? ? ? cx,

? ? ? ? ? ? ? ? ? ? baselineY,

? ? ? ? ? ? ? ? ? ? mSelectTextPaint);

? ? ? ? } else if (hasScheme) {

? ? ? ? ? ? canvas.drawText(String.valueOf(calendar.getDay()),

? ? ? ? ? ? ? ? ? ? cx,

? ? ? ? ? ? ? ? ? ? baselineY,

? ? ? ? ? ? ? ? ? ? calendar.isCurrentDay() ? mCurDayTextPaint :

? ? ? ? ? ? ? ? ? ? ? ? ? ? calendar.isCurrentMonth() && isInRange && isEnable? mSchemeTextPaint : mOtherMonthTextPaint);

? ? ? ? } else {

? ? ? ? ? ? canvas.drawText(String.valueOf(calendar.getDay()), cx, baselineY,

? ? ? ? ? ? ? ? ? ? calendar.isCurrentDay() ? mCurDayTextPaint :

? ? ? ? ? ? ? ? ? ? ? ? ? ? calendar.isCurrentMonth() && isInRange && isEnable? mCurMonthTextPaint : mOtherMonthTextPaint);

? ? ? ? }

? ? }

CalendarColors.java代碼如下(可自定義顏色):

public static final int middleColor = Color.rgb(255, 221, 217);

? ? public static final int selectedColor = Color.rgb(255, 83, 67);

? ? public static final int middleTxtColor = Color.rgb(64, 64, 64);

? ? public static final int selectedTxtColor = Color.rgb(255, 255, 255);

6.日期選擇范圍,結(jié)束日期小于開始日期時,依舊繪制(修改源碼三步驟)

在github地址:https://github.com/huanghaibin-dev/CalendarView,下載好項目,運行起來,接下來按照步驟修改

(1)CalendarUtil.java的differ(Calendar calendar1, Calendar calendar2)方法修改成如下:

/**

? ? * 運算 大日期減小日期

? ? * test Pass

? ? *

? ? * @param calendar1 calendar1 第二次點擊的日期

? ? * @param calendar2 calendar2 第一次點擊的日期

? ? * @return 大日期減小日期

? ? */

? ? static int differ(Calendar calendar1, Calendar calendar2) {

? ? ? ? if (calendar1 == null) {

? ? ? ? ? ? return Integer.MIN_VALUE;

? ? ? ? }

? ? ? ? if (calendar2 == null) {

? ? ? ? ? ? return Integer.MAX_VALUE;

? ? ? ? }

? ? ? ? java.util.Calendar date = java.util.Calendar.getInstance();

? ? ? ? date.set(calendar1.getYear(), calendar1.getMonth() - 1, calendar1.getDay());//

? ? ? ? long startTimeMills = date.getTimeInMillis();//獲得起始時間戳

? ? ? ? date.set(calendar2.getYear(), calendar2.getMonth() - 1, calendar2.getDay());//

? ? ? ? long endTimeMills = date.getTimeInMillis();//獲得結(jié)束時間戳

? ? ? ? if (startTimeMills < endTimeMills) {

? ? ? ? ? ? return (int) ((endTimeMills - startTimeMills) / ONE_DAY);

? ? ? ? } else {

? ? ? ? ? ? return (int) ((startTimeMills - endTimeMills) / ONE_DAY);

? ? ? ? }

? ? }

(2)RangeMonthView.java的onClick(View v)方法,修改某行代碼即可,改成如下:(RangeWeekView.java同理)

//大概在168行,因為前面有改過某些代碼,不知道準確行數(shù)了,如下代碼

int compare = calendar.compareTo(mDelegate.mSelectedStartRangeCalendar);

//改成如下代碼:(原因:比較兩次日期大小,當(dāng)?shù)诙吸c擊日期小于第一次點擊日期時,會返回負數(shù),反之會放回1,相等時放回0)

int compare = calendar.compareTo(mDelegate.mSelectedStartRangeCalendar);

? ? ? ? ? ? if (compare < 0) {

? ? ? ? ? ? ? ? compare = 1;

? ? ? ? ? ? }

(3)RangeMonthView.java的isCalendarSelected(Calendar calendar),修改成如下代碼:(RangeWeekView.java同理)

? ? /**

? ? * 日歷是否被選中

? ? *

? ? * @param calendar calendar

? ? * @return 日歷是否被選中

? ? */

? ? protected boolean isCalendarSelected(Calendar calendar) {

? ? ? ? if (mDelegate.mSelectedStartRangeCalendar == null) {

? ? ? ? ? ? return false;

? ? ? ? }

? ? ? ? if (onCalendarIntercept(calendar)) {

? ? ? ? ? ? return false;

? ? ? ? }

? ? ? ? if (mDelegate.mSelectedEndRangeCalendar == null) {

? ? ? ? ? ? return calendar.compareTo(mDelegate.mSelectedStartRangeCalendar) == 0;

? ? ? ? }

? ? ? ? /*

? ? ? ? *原先的代碼如下:

? ? ? ? *(當(dāng)calendar在大于等于“第一次點擊日期”而且小于等于“第二次點擊日期”時為true

? ? ? ? *這個邏輯對于我們“第一次點擊日期”小于“第二次點擊日期”就會返回false了)

? ? ? ? *? return calendar.compareTo(mDelegate.mSelectedStartRangeCalendar) >= 0 &&

? ? ? ? *? ? ? calendar.compareTo(mDelegate.mSelectedEndRangeCalendar) <= 0;

? ? ? ? * */

? ? ? ? return (calendar.compareTo(mDelegate.mSelectedStartRangeCalendar) >= 0 &&calendar.compareTo(mDelegate.mSelectedEndRangeCalendar) <= 0) ||

? ? ? ? ? ? ? ? (calendar.compareTo(mDelegate.mSelectedEndRangeCalendar) >= 0 && calendar.compareTo(mDelegate.mSelectedStartRangeCalendar) <= 0);

? ? }

前方bug注意:修改三步驟后,結(jié)束日期小于開始日期是繪制了,但是不知道你選中的時間范圍是什么,解決這個bug,按如下代碼修改即可:

1.CalendarViewDelegate.java的getSelectCalendarRange()方法,當(dāng)結(jié)束日期小于開始日期時,置換startTimeMills、endTimeMills即可,改成如下:

? /**

? ? * 獲得選中范圍

? ? *

? ? * @return 選中范圍

? ? */

? ? final List<Calendar> getSelectCalendarRange() {

? ? ? ? if (mSelectMode != SELECT_MODE_RANGE) {

? ? ? ? ? ? return null;

? ? ? ? }

? ? ? ? List<Calendar> calendars = new ArrayList<>();

? ? ? ? if (mSelectedStartRangeCalendar == null ||

? ? ? ? ? ? ? ? mSelectedEndRangeCalendar == null) {

? ? ? ? ? ? return calendars;

? ? ? ? }

? ? ? ? final long ONE_DAY = 1000 * 3600 * 24;

? ? ? ? java.util.Calendar date = java.util.Calendar.getInstance();

? ? ? ? date.set(mSelectedStartRangeCalendar.getYear(),

? ? ? ? ? ? ? ? mSelectedStartRangeCalendar.getMonth() - 1,

? ? ? ? ? ? ? ? mSelectedStartRangeCalendar.getDay());//

? ? ? ? long startTimeMills = date.getTimeInMillis();//獲得起始時間戳

? ? ? ? date.set(mSelectedEndRangeCalendar.getYear(),

? ? ? ? ? ? ? ? mSelectedEndRangeCalendar.getMonth() - 1,

? ? ? ? ? ? ? ? mSelectedEndRangeCalendar.getDay());//

? ? ? ? long endTimeMills = date.getTimeInMillis();

? ? ? ? //新增的代碼,開始日期大于結(jié)束日期,置換

? ? ? ? if (startTimeMills > endTimeMills) {

? ? ? ? ? ? Long interTimeMills;

? ? ? ? ? ? interTimeMills = startTimeMills;

? ? ? ? ? ? startTimeMills = endTimeMills;

? ? ? ? ? ? endTimeMills = interTimeMills;

? ? ? ? }

? ? ? ? for (long start = startTimeMills; start <= endTimeMills; start += ONE_DAY) {

? ? ? ? ? ? date.setTimeInMillis(start);

? ? ? ? ? ? Calendar calendar = new Calendar();

? ? ? ? ? ? calendar.setYear(date.get(java.util.Calendar.YEAR));

? ? ? ? ? ? calendar.setMonth(date.get(java.util.Calendar.MONTH) + 1);

? ? ? ? ? ? calendar.setDay(date.get(java.util.Calendar.DAY_OF_MONTH));

? ? ? ? ? ? if (mCalendarInterceptListener != null &&

? ? ? ? ? ? ? ? ? ? mCalendarInterceptListener.onCalendarIntercept(calendar)) {

? ? ? ? ? ? ? ? continue;

? ? ? ? ? ? }

? ? ? ? ? ? LunarCalendar.setupLunarCalendar(calendar);

? ? ? ? ? ? calendars.add(calendar);

? ? ? ? }

? ? ? ? addSchemesFromMap(calendars);

? ? ? ? return calendars;

? ? }

改好后,運行測試?,F(xiàn)在問題來了,怎么加入到項目里呢?原先我們引入日歷這樣子:

implementation 'com.haibin:calendarview:3.6.5'

改好源碼后,怎么引入到項目里面呢?我的做法是把calendarview一整個libar引入到項目中,步驟如下:

1.選中calendarview右鍵——Show in Explorer(就是找到calendarview的路徑);

2.選中項目(自己的項目)右鍵——New——Module——Import Gradle Project——Next——選擇calendarview路徑——Next;

3.修改calendarview的gradle,

calendarview、minSdkVersion、targetSdkVersion、versionCode、versionName這些值改成跟項目的一樣,

把compile改成implementation,androidTestCompile改成androidTestImplementation,testCompiletestImplementation,

注意appcompat-v7、recyclerview-v7、junit版本號跟項目一致

4.clean、rebuild一下,運行即可

7.左右滑動切換月份實時顯示當(dāng)前年月

我入的坑:使用的是“范圍選擇”,要求左右滑動日歷(點擊<>)時,要顯示當(dāng)前年月,不然用戶不知道滑動到哪里去了:

只需繼承CalendarView.OnMonthChangeListener的

@Override

public void onMonthChange(int year, int month) {

? //顯示年月

}

注意:記得添加calendarView.setOnMonthChangeListener(this);

8.設(shè)置今天之后的日期不可點且置灰色,重點OnCalendarInterceptListener(select_mode要設(shè)置成支持攔截)

//設(shè)置日期攔截事件

? ? @Override

? ? public boolean onCalendarIntercept(Calendar calendar) {

? ? ? ? String str = calendar.getYear() + "-" + (calendar.getMonth() < 10 ? "0" + calendar.getMonth() : calendar.getMonth()) + "-" + (calendar.getDay() < 10 ? "0" + calendar.getDay() : calendar.getDay());

? ? ? ? String now= binding.cvHomeDormitoryAttendanceCalendarView.getCurYear() + "-" + binding.cvHomeDormitoryAttendanceCalendarView.getCurMonth() + "-" + binding.cvHomeDormitoryAttendanceCalendarView.getCurDay();

? ? ? ? return TimeUtils.NowCompare(now, str);//現(xiàn)在日期,點擊日期進行對比,點擊日期>現(xiàn)在日期為true即攔截

? ? }

? ? @Override

? ? public void onCalendarInterceptClick(Calendar calendar, boolean isClick) {

? ? ? ? //點擊攔截的日期回調(diào),isClick為true時表示攔截到設(shè)置條件的日期,可以做相應(yīng)提示

? ? }

目前入過的坑就是以上這些了,并且解決,希望能幫助遇到同樣問題的你,后面若遇到新問題,會繼續(xù)更新!

————————————————

版權(quán)聲明:本文為CSDN博主「週莫」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。

原文鏈接:https://blog.csdn.net/weixin_40420578/article/details/96485028

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容