当前位置:   article > 正文

android自定义选年控件,Android精美日历控件CalendarView自定义使用完全解析

mcalendarview.scrolltonext(false);//下个月

项目github地址

此框架采用组合的方式,各个模块互相独立,可自由采用各种提供的控件组合,完全自定义自己需要的UI,周视图和月视图可通过简单自定义任意自由绘制,不怕美工提需求!!!下面教程将介绍如何实现3个API,自定义Canvas绘制日历

CalendarView的优势:

1、热插拔设计,根据不同的UI需求完全自定义UI,简单几步即可实现,自定义事件日历标记、颜色、农历等

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

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

4、不要再问可不可以不显示其它月份的日期,可以!!!,你可以任意配置到你喜欢为止;所以也不要问其它什么周末可不可以显示灰色,其它什么可不可以,只要你稍微懂Canvas的API,这个控件真的可以!!!,UI是万能绘制的

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

Gradle

compile 'com.haibin:calendarview:3.2.0'

com.haibin

calendarview

3.2.0

pom

混淆proguard-rules

-keepclasseswithmembers class * {

public (android.content.Context);

}

国际惯例,先上一个自定义效果图,结尾还有几个其它效果图,可自己自定义

0aa8ebfeb682

meizu.png

0aa8ebfeb682

meizu_shrink.png

各个类功能介绍

CalendarLayout

这是个辅助类,负责CalendarView的收缩控制功能,如果不需要收缩功能,无需使用它,一般使用教程如下

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">

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:month_view_show_mode="mode_only_current"

app:year_view_scheme_color="#f17706"/>

android:id="@+id/recyclerView"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@color/content_background" />

CalendarLayout api

public void expand(); //展开

public void shrink(); //收缩

public boolean isExpand();//是否已经展开

CalendarView

真正的日历类,可以自行通过attr配置

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

CalendarView api

public int getCurDay(); //今天

public int getCurMonth(); //当前的月份

public int getCurYear(); //今年

public void showSelectLayout(final int year); //快速弹出年份选择月份

public void closeSelectLayout(final int position); //关闭选择年份并跳转日期

/**

* 设置日期范围

*

* @param minYear 最小年份

* @param minYearMonth 最小年份对应月份

* @param maxYear 最大月份

* @param maxYearMonth 最大月份对应月份

*/

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);//滚动到指定日期

/**

* 设置背景色

*

* @param monthLayoutBackground 月份卡片的背景色

* @param weekBackground 星期栏背景色

* @param lineBg 线的颜色

*/

public void setBackground(int monthLayoutBackground, int weekBackground, int lineBg)

/**

* 设置文本颜色

*

* @param curMonthTextColor 当前月份字体颜色

* @param otherMonthColor 其它月份字体颜色

* @param lunarTextColor 农历字体颜色

*/

public void setTextColor(int curMonthTextColor,int otherMonthColor,int lunarTextColor)

/**

* 设置选择的效果

*

* @param style 选中的style CalendarCardView.STYLE_FILL or CalendarCardView.STYLE_STROKE

* @param selectedThemeColor 选中的标记颜色

* @param selectedTextColor 选中的字体颜色

*/

public void setSelectedColor(int style, int selectedThemeColor, int selectedTextColor)

/**

* 设置标记的色

*

* @param style 标记的style CalendarCardView.STYLE_FILL or CalendarCardView.STYLE_STROKE

* @param schemeColor 标记背景色

* @param schemeTextColor 标记字体颜色

*/

public void setSchemeColor(int style, int schemeColor, int schemeTextColor)

/**

* 设置背景色

*

* @param yearViewBackground 年份卡片的背景色

* @param weekBackground 星期栏背景色

* @param lineBg 线的颜色

*/

public void setBackground(int yearViewBackground, int weekBackground, int lineBg)

这个控件的特别之处就是它的UI是可以交给客户端自由绘制的,因此可以自由发挥想象力,绘制你需要的日历效果UI

接下来介绍如何完全自定义日历,自定义日历需要同时自定义月视图和周视图,代码几乎一样,需要实现三个回调函数即可,如下:

onDrawSelected

onDrawScheme

onDrawText

/**

* 首先继承月视图,假如我们想实现高仿魅族的日历

*/

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);

}

/**

* 绘制选中的日子

* @param canvas canvas

* @param calendar 日历日历calendar

* @param x 日历Card x起点坐标

* @param y 日历Card y起点坐标

* @param hasScheme hasScheme 非标记的日期

* @return 返回true 则会继续绘制onDrawScheme,因为这里背景色不是是互斥的,所以返回true,返回false,则点击scheme标记的日子,则不继续绘制onDrawScheme,自行选择即可

*/

@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;

}

/**

* 绘制标记的事件日子

* @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) {

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);

}

/**

* 绘制文本

* @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 (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);

}

}

/**

* 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);

}

}

实现自定义周视图,周视图除了三个回调函数少了一个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);

}

/**

*

* @param canvas canvas

* @param calendar 日历日历calendar

* @param x 日历Card x起点坐标

* @param hasScheme hasScheme 非标记的日期

* @return true 则绘制onDrawScheme,因为这里背景色不是是互斥的

*/

@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);

}

}

/**

* 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);

}

}

最后通过CalendarView两个attr配置class路径即可,是不是很像自定义Behavior?

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

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

最后各种自定义UI效果自由欣赏,源码都在demo

0aa8ebfeb682

color_expand.png

0aa8ebfeb682

color_shrink.png

0aa8ebfeb682

index_expand.png

0aa8ebfeb682

year_view.png

0aa8ebfeb682

![simple_shrink.png](http://upload-images.jianshu.io/upload_images/1509545-0c19422c5049d601.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/800)

建议clone APP Demo,里面作者实现了几种类型的风格,可以参考实现

项目开源地址,一点贡献

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/543220
推荐阅读
相关标签
  

闽ICP备14008679号