Android開源的精美日曆控件,熱插拔設計的萬能自定義UI

Android開源的精美日曆控件,熱插拔設計的萬能自定義UIandroid

UI框架應該邏輯與界面實現分離,該日曆控件使用了熱插拔的設計 ,簡單幾步便可實現你須要的UI效果,熱插拔的思想是你提供你的實現,我提供個人插座接口,與自定義Behavior是同樣的思想。git

CalendarView的優點:github

一、熱插拔設計,根據不一樣的UI需求徹底自定義UI,簡單幾步便可實現,自定義事件日曆標記、顏色、農曆等canvas

二、徹底Canvas繪製,性能和速度都很不錯,相比大多數基於GridView或RecyclerView實現的佔用內存更低,啓動速度更快app

三、支持收縮、展開、快速年月份選擇等框架

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

先看看控件的attr函數

<declare-styleable name="CalendarView">

        <attr name="calendar_card_view" format="color" /> <!--熱插拔自定義類路徑-->

        <attr name="week_background" format="color" /> <!--星期欄的背景-->
        <attr name="week_text_color" format="color" /> <!--星期欄文本顏色-->

        <attr name="current_day_text_color" format="color" /> <!--今天的文本顏色-->

        <attr name="day_text_size" format="string" /> <!--天數文本大小-->
        <attr name="lunar_text_size" format="string" /> <!--農曆文本大小-->

        <attr name="scheme_text" format="string" /> <!--標記文本-->
        <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_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="min_year" format="integer" />  <!--最小年份1900-->
        <attr name="max_year" format="integer" /> <!--最大年份2099-->
        
</declare-styleable>

 

XML用法oop

若是須要在日曆控件下方使用其它控件,使用CalendarLayout控件便可,calendar_content_view_id爲其它控件的id,支持任意控件,如RecyclerView、ListView。CalendarView的calendar_card_view爲任意自定義實現的日曆繪製控件路徑。性能

<com.haibin.calendarview.CalendarLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#fff"
        app:calendar_content_view_id="@+id/linearView">

        <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:other_month_text_color="#e1e1e1"
            app:scheme_text_color="#333"
            app:scheme_theme_color="#128c4b"
            app:selected_lunar_text_color="#CFCFCF"
            app:calendar_card_view="com.haibin.calendarviewproject.meizu.MeiZuCalendarCardView"
            app:selected_text_color="#333"
            app:selected_theme_color="#108cd4"
            app:week_background="#fff"
            app:week_text_color="#111" />

        <LinearLayout
            android:id="@+id/linearView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/content_background"
            android:clickable="true"
            android:orientation="vertical"
            tools:ignore="KeyboardInaccessibleWidget"/>
        </LinearLayout>
</com.haibin.calendarview.CalendarLayout>

 

熟悉一下這幾個簡單的特性,看看日曆內容界面的繪製BaseCalendarCardView,根據需求實現如下部分方法便可

/**
     * 開始繪製前的回調鉤子,這裏作一些初始化的操做,每次繪製只調用一次,性能高效
     * 沒有須要可忽略不實現
     * 例如:
     * 一、須要繪製圓形標記事件背景,能夠在這裏計算半徑
     * 二、繪製矩形選中效果,也能夠在這裏計算矩形寬和高
     */
    protected void onPreviewHook() {
        // TODO: 2017/11/16
    }


    /**
     * 循環繪製開始的回調,不須要可忽略
     * 繪製每一個日曆項的循環,用來計算baseLine、圓心座標等均可以在這裏實現
     *
     * @param x 日曆Card x起點座標
     * @param y 日曆Card y起點座標
     */
    protected void onLoopStart(int x, int y) {
        // TODO: 2017/11/16  
    }

    /**
     * 繪製選中的日期
     *
     * @param canvas    canvas
     * @param calendar  日曆日曆calendar
     * @param x         日曆Card x起點座標
     * @param y         日曆Card y起點座標
     * @param hasScheme hasScheme 非標記的日期
     */
    protected abstract void onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme);

    /**
     * 繪製標記的日期UI
     *
     * @param canvas   canvas
     * @param calendar 日曆calendar
     * @param x        日曆Card x起點座標
     * @param y        日曆Card y起點座標
     */
    protected abstract void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y);


    /**
     * 繪製日曆文本
     *
     * @param canvas     canvas
     * @param calendar   日曆calendar
     * @param x          日曆Card x起點座標
     * @param y          日曆Card y起點座標
     * @param hasScheme  是不是標記的日期
     * @param isSelected 是否選中
     */
    protected abstract void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected);

舉個例子:若是你的需求是相似魅族日曆的UI,那麼第一步,繼承BaseCalendarCardView,而後實現onDrawSelected、onDrawScheme、onDrawText三個回調函數便可

public class MeiZuCalendarCardView extends BaseCalendarCardView {

    private Paint mTextPaint = new Paint();
    private Paint mSchemeBasicPaint = new Paint();
    private float mRadio;
    private int mPadding;
    private float mSchemeBaseLine;

    public MeiZuCalendarCardView(Context context) {
        super(context);

        mTextPaint.setTextSize(dipToPx(context, 8));
        mTextPaint.setColor(0xff111111);
        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);

    }

    /**
     * 繪製選中的日期
     *
     * @param canvas    canvas
     * @param calendar  日曆日曆calendar
     * @param x         日曆Card x起點座標
     * @param y         日曆Card y起點座標
     * @param hasScheme hasScheme 非標記的日期
     */
    @Override
    protected void 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);
    }

    /**
     * 繪製標記的日期UI 這裏魅族界面不須要繪製多彩風格,忽略便可
     *
     * @param canvas   canvas
     * @param calendar 日曆calendar
     * @param x        日曆Card x起點座標
     * @param y        日曆Card y起點座標
     */
    @Override
    protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {

    }

    /**
     * 繪製日曆文本
     *
     * @param canvas     canvas
     * @param calendar   日曆calendar
     * @param x          日曆Card x起點座標
     * @param y          日曆Card y起點座標
     * @param hasScheme  是不是標記的日期
     * @param isSelected 是否選中
     */
    @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 (hasScheme) {
            //繪製日期
            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
                    calendar.isCurrentDay() ? mCurDayTextPaint :
                            calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
            //繪製農曆
            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mCurMonthLunarTextPaint);
            mTextPaint.setColor(Color.WHITE);
            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);

        } 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, mCurMonthLunarTextPaint);
        }
    }

    /**
     * dp轉px
     *
     * @param context context
     * @param dpValue dp
     * @return px
     */
    private static int dipToPx(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}

第二步:使用方法、app:calendar_card_view="xxx.xx.MeiZuCalendarCardView"

魅族風格日曆效果預覽

 魅族風格                    魅族收縮

快速年月份選擇

快速月份選擇

其它做者實現的幾個UI效果預覽,簡單源碼都在demo能夠看到

多彩風格界面

多彩風格                    收縮

下標風格界面

下標風格                    下標收縮

簡單沒有農曆界面

簡單風格                    收縮界面

更多參考用法移步APP Demo,裏面做者實現了幾種類型的風格,能夠參考實現

項目開源地址

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

若是以爲源碼能夠請給個star,源碼註釋完善,簡單易懂,容易學習。

相關文章
相關標籤/搜索