天天看點

android gridview控件使用詳解_Android精美月曆控件CalendarView自定義使用完全解析

android gridview控件使用詳解_Android精美月曆控件CalendarView自定義使用完全解析

秦子帥 明确目标,每天進步一點點.....

android gridview控件使用詳解_Android精美月曆控件CalendarView自定義使用完全解析

作者 |  黃海彬

位址 | https://juejin.im/post/5a6743836fb9a01caa20aefc

詳解

此架構采用組合的方式,各個子產品互相獨立,可自由采用各種提供的控件組合,完全自定義自己需要的UI,周視圖和月視圖可通過簡單自定義任意自由繪制,不怕美工提需求!!!下面教程将介紹如何實作3個API,自定義Canvas繪制月曆

CalendarView的優勢:

1、熱插拔設計,根據不同的UI需求完全自定義UI,簡單幾步即可實作,自定義事件月曆标記、顔色、農曆等

2、完全Canvas繪制,性能和速度都很不錯,相比大多數基于GridView或RecyclerView實作的占用記憶體更低,啟動速度更快

3、支援收縮、展開、快速年月份選擇等

4、簡潔易懂的源碼,易學習。

Gradle

compile 'com.haibin:calendarview:3.2.9'

<dependency><groupId>com.haibingroupId><artifactId>calendarviewartifactId><version>3.2.9version><type>pomtype>dependency>

混淆proguard-rules

-keepclasseswithmembers class * {public (android.content.Context); }

國際慣例,先上一個自定義效果圖,結尾還有幾個其它效果圖,可自己自定義

android gridview控件使用詳解_Android精美月曆控件CalendarView自定義使用完全解析
android gridview控件使用詳解_Android精美月曆控件CalendarView自定義使用完全解析

各個類功能介紹

CalendarLayout

這是個輔助類,負責CalendarView的收縮控制功能,如果不需要收縮功能,無需使用它,一般使用教程如下

<com.haibin.calendarview.CalendarLayout         android:id="@+id/calendarLayout"         android:layout_width="match_parent"         android:layout_height="match_parent"         android:orientation="vertical"         android:background="#fff"         app:only_week_view="false"         app:default_status="shrink"         app:calendar_content_view_id="@+id/recyclerView">         <com.haibin.calendarview.CalendarView             android:id="@+id/calendarView"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:background="#fff"             app:current_month_text_color="#333333"             app:current_month_lunar_text_color="#CFCFCF"             app:min_year="2004"             app:max_year="2020"             app:other_month_text_color="#e1e1e1"             app:other_month_lunar_text_color="#e1e1e1"             app:scheme_text="假"             app:week_start_with="mon"             app:scheme_text_color="#333"             app:scheme_theme_color="#128c4b"             app:selected_lunar_text_color="#CFCFCF"             app:month_view="com.haibin.calendarviewproject.meizu.MeiZuMonthView"             app:week_view="com.haibin.calendarviewproject.meizu.MeizuWeekView"             app:selected_text_color="#333"             app:selected_theme_color="#108cd4"             app:week_background="#fff"             app:week_text_color="#111"             app:year_view_day_text_color="#333333"             app:year_view_day_text_size="9sp"             app:year_view_month_text_color="#ff0000"             app:year_view_month_text_size="20sp"             app:month_view_show_mode="mode_only_current"             app:year_view_scheme_color="#f17706"/>         <com.haibin.calendarviewproject.group.GroupRecyclerView             android:id="@+id/recyclerView"             android:layout_width="match_parent"             android:layout_height="match_parent"             android:background="@color/content_background" />com.haibin.calendarview.CalendarLayout>

CalendarLayout api

public void expand(); //展開public void shrink(); //收縮public boolean isExpand();//是否已經展開

<attr name="calendar_show_mode"><enum name="both_month_week_view" value="0" /><enum name="only_week_view" value="1" /><enum name="only_month_view" value="2" />attr><attr name="default_status"><enum name="expand" value="0" /> <enum name="shrink" value="1" />attr><attr name="calendar_content_view_id" format="integer" />

CalendarView

真正的月曆類,可以自行通過attr配置

<com.haibin.calendarview.CalendarView             android:id="@+id/calendarView"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:background="#fff"             app:current_month_text_color="#333333"             app:current_month_lunar_text_color="#CFCFCF"             app:min_year="2004"             app:max_year="2020"             app:other_month_text_color="#e1e1e1"             app:other_month_lunar_text_color="#e1e1e1"             app:scheme_text="假"             app:scheme_text_color="#333"             app:scheme_theme_color="#128c4b"             app:selected_lunar_text_color="#CFCFCF"             app:month_view="com.haibin.calendarviewproject.meizu.MeiZuMonthView"             app:week_view="com.haibin.calendarviewproject.meizu.MeizuWeekView"             app:selected_text_color="#333"             app:selected_theme_color="#108cd4"             app:week_background="#fff"             app:week_text_color="#111"             app:year_view_day_text_color="#333333"             app:year_view_day_text_size="9sp"             app:year_view_month_text_color="#ff0000"             app:year_view_month_text_size="20sp"             app:year_view_scheme_color="#f17706"/>

完整attr

<declare-styleable name="CalendarView"><attr name="week_background" format="color" /><attr name="week_line_background" format="color" /><attr name="week_text_color" format="color" /><attr name="week_bar_view" format="string" /><attr name="month_view" format="string" /><attr name="week_view" format="string" /><attr name="scheme_text" format="string" /><attr name="day_text_size" format="dimension" /><attr name="lunar_text_size" format="dimension" /><attr name="calendar_height" format="dimension" /><attr name="scheme_text_color" format="color" /><attr name="scheme_month_text_color" format="color" /><attr name="scheme_lunar_text_color" format="color" /><attr name="scheme_theme_color" format="color" /><attr name="selected_theme_color" format="color" /><attr name="selected_text_color" format="color" /><attr name="selected_lunar_text_color" format="color" /><attr name="current_day_text_color" format="color" /><attr name="current_day_lunar_text_color" format="color" /><attr name="current_month_text_color" format="color" /><attr name="other_month_text_color" format="color" /><attr name="current_month_lunar_text_color" format="color" /><attr name="other_month_lunar_text_color" format="color" /><attr name="year_view_month_text_size" format="dimension" /><attr name="year_view_day_text_size" format="dimension" /><attr name="year_view_month_text_color" format="color" /><attr name="year_view_day_text_color" format="color" /><attr name="year_view_scheme_color" format="color" /><attr name="year_view_background" format="color" /><attr name="min_year" format="integer" /><attr name="max_year" format="integer" /><attr name="min_year_month" format="integer" /><attr name="max_year_month" format="integer" /><attr name="month_view_show_mode"><enum name="mode_all" value="0" /> <enum name="mode_only_current" value="1" /> <enum name="mode_fix" value="2" /> attr><attr name="week_start_with"><enum name="sun" value="1" /><enum name="mon" value="2" /><enum name="sat" value="7" />attr>declare-styleable>

CalendarView api

public int getCurDay(); //今天public int getCurMonth(); //目前的月份public int getCurYear(); //今年public void showSelectLayout(final int year); //快速彈出年份選擇月份public void closeSelectLayout(final int position); //關閉選擇年份并跳轉日期public void setRange(int minYear, int minYearMonth,int maxYear, int maxYearMonth) public void setOnYearChangeListener(OnYearChangeListener listener);//年份切換事件public void setOnDateSelectedListener(OnDateSelectedListener listener);//日期選擇事件public void setSchemeDate(List mSchemeDate);//标記日期public void update();//動态更新public Calendar getSelectedCalendar(); //擷取選擇的日期public void scrollToPre();//滾動到上一個月public void scrollToNext();//滾動到下一個月public void scrollToCalendar(int year, int month, int day);//滾動到指定日期public void setBackground(int monthLayoutBackground, int weekBackground, int lineBg)public void setTextColor(int curMonthTextColor,int otherMonthColor,int lunarTextColor)public void setSelectedColor(int style, int selectedThemeColor, int selectedTextColor)public void setSchemeColor(int style, int schemeColor, int schemeTextColor)public void setBackground(int yearViewBackground, int weekBackground, int lineBg)

這個控件的特别之處就是它的UI是可以交給用戶端自由繪制的,是以可以自由發揮想象力,繪制你需要的月曆效果UI

接下來介紹如何完全自定義月曆,自定義月曆需要同時自定義月視圖和周視圖,代碼幾乎一樣,需要實作三個回調函數即可,如下:

onDrawSelectedonDrawSchemeonDrawText

public class MeiZuMonthView extends MonthView {        private Paint mTextPaint = new Paint();        private Paint mSchemeBasicPaint = new Paint();    private float mRadio;    private int mPadding;    private float mSchemeBaseLine;    public MeiZuMonthView(Context context) {        super(context);        mTextPaint.setTextSize(dipToPx(context, 8));        mTextPaint.setColor(0xffffffff);        mTextPaint.setAntiAlias(true);        mTextPaint.setFakeBoldText(true);        mSchemeBasicPaint.setAntiAlias(true);        mSchemeBasicPaint.setStyle(Paint.Style.FILL);        mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);        mSchemeBasicPaint.setFakeBoldText(true);        mRadio = dipToPx(getContext(), 7);        mPadding = dipToPx(getContext(), 4);        Paint.FontMetrics metrics = mSchemeBasicPaint.getFontMetrics();        mSchemeBaseLine = mRadio - metrics.descent + (metrics.bottom - metrics.top) / 2 + dipToPx(getContext(), 1);    }        @Override    protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {        mSelectedPaint.setStyle(Paint.Style.FILL);        mSelectedPaint.setColor(0x80cfcfcf);        canvas.drawRect(x + mPadding, y + mPadding, x + mItemWidth - mPadding, y + mItemHeight - mPadding, mSelectedPaint);        return true;    }        @Override    protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {        mSchemeBasicPaint.setColor(calendar.getSchemeColor());        canvas.drawCircle(x + mItemWidth - mPadding - mRadio / 2, y + mPadding + mRadio, mRadio, mSchemeBasicPaint);        canvas.drawText(calendar.getScheme(), x + mItemWidth - mPadding - mRadio, y + mPadding + mSchemeBaseLine, mTextPaint);    }        @Override    protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {        int cx = x + mItemWidth / 2;        int top = y - mItemHeight / 6;        if (isSelected) {//優先繪制選擇的            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    mSelectTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mSelectedLunarTextPaint);        } else if (hasScheme) {//否則繪制具有标記的            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mCurMonthLunarTextPaint);        } else {//最好繪制普通文本            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    calendar.isCurrentDay() ? mCurDayTextPaint :                            calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,                    calendar.isCurrentDay() ? mCurDayLunarTextPaint :                            calendar.isCurrentMonth() ? mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);        }    }        private static int dipToPx(Context context, float dpValue) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (dpValue * scale + 0.5f);    }}

實作自定義周視圖,周視圖除了三個回調函數少了一個y參數,其它一樣,因為周視圖隻有一行,是以可直接copy MonthView的代碼,令y=0即可,如下

public class MeizuWeekView extends WeekView {    private Paint mTextPaint = new Paint();    private Paint mSchemeBasicPaint = new Paint();    private float mRadio;    private int mPadding;    private float mSchemeBaseLine;    public MeizuWeekView(Context context) {        super(context);        mTextPaint.setTextSize(dipToPx(context, 8));        mTextPaint.setColor(0xffffffff);        mTextPaint.setAntiAlias(true);        mTextPaint.setFakeBoldText(true);        mSchemeBasicPaint.setAntiAlias(true);        mSchemeBasicPaint.setStyle(Paint.Style.FILL);        mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);        mSchemeBasicPaint.setColor(0xffed5353);        mSchemeBasicPaint.setFakeBoldText(true);        mRadio = dipToPx(getContext(), 7);        mPadding = dipToPx(getContext(), 4);        Paint.FontMetrics metrics = mSchemeBasicPaint.getFontMetrics();        mSchemeBaseLine = mRadio - metrics.descent + (metrics.bottom - metrics.top) / 2 + dipToPx(getContext(), 1);    }        @Override    protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme) {        mSelectedPaint.setStyle(Paint.Style.FILL);        mSelectedPaint.setColor(0x80cfcfcf);        canvas.drawRect(x + mPadding, mPadding, x + mItemWidth - mPadding, mItemHeight - mPadding, mSelectedPaint);        return true;    }    @Override    protected void onDrawScheme(Canvas canvas, Calendar calendar, int x) {        mSchemeBasicPaint.setColor(calendar.getSchemeColor());        canvas.drawCircle(x + mItemWidth - mPadding - mRadio / 2, mPadding + mRadio, mRadio, mSchemeBasicPaint);        canvas.drawText(calendar.getScheme(), x + mItemWidth - mPadding - mRadio, mPadding + mSchemeBaseLine, mTextPaint);    }    @Override    protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {        int cx = x + mItemWidth / 2;        int top = -mItemHeight / 6;        if (isSelected) {            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    mSelectTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mSelectedLunarTextPaint);        } else if (hasScheme) {            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mCurMonthLunarTextPaint);        } else {            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    calendar.isCurrentDay() ? mCurDayTextPaint :                            calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,                    calendar.isCurrentDay() ? mCurDayLunarTextPaint :                            calendar.isCurrentMonth() ? mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);        }    }        private static int dipToPx(Context context, float dpValue) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (dpValue * scale + 0.5f);    }}

最後通過CalendarView兩個attr配置class路徑即可,是不是很像自定義Behavior?

app:month_view="com.haibin.calendarviewproject.meizu.MeiZuMonthView"app:week_view="com.haibin.calendarviewproject.meizu.MeizuWeekView"

最後各種自定義UI效果自由欣賞,源碼都在demo

android gridview控件使用詳解_Android精美月曆控件CalendarView自定義使用完全解析
android gridview控件使用詳解_Android精美月曆控件CalendarView自定義使用完全解析
android gridview控件使用詳解_Android精美月曆控件CalendarView自定義使用完全解析
android gridview控件使用詳解_Android精美月曆控件CalendarView自定義使用完全解析
android gridview控件使用詳解_Android精美月曆控件CalendarView自定義使用完全解析
android gridview控件使用詳解_Android精美月曆控件CalendarView自定義使用完全解析

裡面作者實作了幾種類型的風格,可以參考實作

項目開源位址,一點貢獻

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

---END---

android gridview控件使用詳解_Android精美月曆控件CalendarView自定義使用完全解析

 創作不易,點個“ 在看 ”

android gridview控件使用詳解_Android精美月曆控件CalendarView自定義使用完全解析

繼續閱讀