Android开源的精美日历控件,热插拔设计的万能自定义UI

UI框架应该逻辑与界面实现分离,该日历控件使用了热插拔的设计 ,简单几步便可实现你须要的UI效果,热插拔的思想是你提供你的实现,我提供个人插座接口,与自定义Behavior是同样的思想。

据说第一页无效果图就看不下去了?先上个高仿魅族日历界面

     

项目开源地址

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

CalendarView的优点:

一、热插拔设计,根据不一样的UI需求彻底自定义UI,简单几步便可实现,自定义事件日历标记、颜色、农历等

二、彻底Canvas绘制,性能和速度都很不错,相比大多数基于GridView或RecyclerView实现的占用内存更低,启动速度更快

三、支持收缩、展开、快速年月份选择等

四、简洁易懂的源码,易学习。

先看看控件的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用法

若是须要在日历控件下方使用其它控件,使用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/CalendarViewandroid

若是以为源码能够请给个star,源码注释完善,简单易懂,容易学习。

相关文章
相关标签/搜索