UI框架應(yīng)該邏輯與界面實(shí)現(xiàn)分離,該日歷控件使用了熱插拔的設(shè)計(jì) ,簡(jiǎn)單幾步即可實(shí)現(xiàn)你需要的UI效果,熱插拔的思想是你提供你的實(shí)現(xiàn),我提供我的插座接口,與自定義Behavior是一樣的思想。
聽說第一頁(yè)無效果圖就看不下去了?先上個(gè)高仿魅族日歷界面

魅族界面.png

魅族收縮.png
項(xiàng)目開源地址
https://github.com/huanghaibin-dev/CalendarView
CalendarView的優(yōu)勢(shì):
1、熱插拔設(shè)計(jì),根據(jù)不同的UI需求完全自定義UI,簡(jiǎn)單幾步即可實(shí)現(xiàn),自定義事件日歷標(biāo)記、顏色、農(nóng)歷等
2、完全Canvas繪制,性能和速度都很不錯(cuò),相比大多數(shù)基于GridView或RecyclerView實(shí)現(xiàn)的占用內(nèi)存更低,啟動(dòng)速度更快
3、支持收縮、展開、快速年月份選擇等
4、簡(jiǎn)潔易懂的源碼,易學(xué)習(xí)。
先看看控件的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" /> <!--天數(shù)文本大小-->
<attr name="lunar_text_size" format="string" /> <!--農(nóng)歷文本大小-->
<attr name="scheme_text" format="string" /> <!--標(biāo)記文本-->
<attr name="scheme_text_color" format="color" /> <!--標(biāo)記文本顏色-->
<attr name="scheme_month_text_color" format="color" /> <!--標(biāo)記天數(shù)文本顏色-->
<attr name="scheme_lunar_text_color" format="color" /> <!--標(biāo)記農(nóng)歷文本顏色-->
<attr name="scheme_theme_color" format="color" /> <!--標(biāo)記的顏色-->
<attr name="selected_theme_color" format="color" /> <!--選中顏色-->
<attr name="selected_text_color" format="color" /> <!--選中文本顏色-->
<attr name="selected_lunar_text_color" format="color" /> <!--選中農(nóng)歷文本顏色-->
<attr name="current_month_text_color" format="color" /> <!--當(dāng)前月份的字體顏色-->
<attr name="other_month_text_color" format="color" /> <!--其它月份的字體顏色-->
<attr name="current_month_lunar_text_color" format="color" /> <!--當(dāng)前月份農(nóng)歷節(jié)假日顏色-->
<attr name="other_month_lunar_text_color" format="color" /> <!--其它月份農(nóng)歷節(jié)假日顏色-->
<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為任意自定義實(shí)現(xiàn)的日歷繪制控件路徑。
<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>
熟悉一下這幾個(gè)簡(jiǎn)單的特性,看看日歷內(nèi)容界面的繪制BaseCalendarCardView,根據(jù)需求實(shí)現(xiàn)以下部分方法即可
/**
* 開始繪制前的回調(diào)鉤子,這里做一些初始化的操作,每次繪制只調(diào)用一次,性能高效
* 沒有需要可忽略不實(shí)現(xiàn)
* 例如:
* 1、需要繪制圓形標(biāo)記事件背景,可以在這里計(jì)算半徑
* 2、繪制矩形選中效果,也可以在這里計(jì)算矩形寬和高
*/
protected void onPreviewHook() {
// TODO: 2017/11/16
}
/**
* 循環(huán)繪制開始的回調(diào),不需要可忽略
* 繪制每個(gè)日歷項(xiàng)的循環(huán),用來計(jì)算baseLine、圓心坐標(biāo)等都可以在這里實(shí)現(xiàn)
*
* @param x 日歷Card x起點(diǎn)坐標(biāo)
* @param y 日歷Card y起點(diǎn)坐標(biāo)
*/
protected void onLoopStart(int x, int y) {
// TODO: 2017/11/16
}
/**
* 繪制選中的日期
*
* @param canvas canvas
* @param calendar 日歷日歷calendar
* @param x 日歷Card x起點(diǎn)坐標(biāo)
* @param y 日歷Card y起點(diǎn)坐標(biāo)
* @param hasScheme hasScheme 非標(biāo)記的日期
*/
protected abstract void onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme);
/**
* 繪制標(biāo)記的日期UI
*
* @param canvas canvas
* @param calendar 日歷calendar
* @param x 日歷Card x起點(diǎn)坐標(biāo)
* @param y 日歷Card y起點(diǎn)坐標(biāo)
*/
protected abstract void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y);
/**
* 繪制日歷文本
*
* @param canvas canvas
* @param calendar 日歷calendar
* @param x 日歷Card x起點(diǎn)坐標(biāo)
* @param y 日歷Card y起點(diǎn)坐標(biāo)
* @param hasScheme 是否是標(biāo)記的日期
* @param isSelected 是否選中
*/
protected abstract void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected);
舉個(gè)例子:如果你的需求是類似魅族日歷的UI,那么第一步,繼承BaseCalendarCardView,然后實(shí)現(xiàn)onDrawSelected、onDrawScheme、onDrawText三個(gè)回調(diào)函數(shù)即可
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起點(diǎn)坐標(biāo)
* @param y 日歷Card y起點(diǎn)坐標(biāo)
* @param hasScheme hasScheme 非標(biāo)記的日期
*/
@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);
}
/**
* 繪制標(biāo)記的日期UI 這里魅族界面不需要繪制多彩風(fēng)格,忽略即可
*
* @param canvas canvas
* @param calendar 日歷calendar
* @param x 日歷Card x起點(diǎn)坐標(biāo)
* @param y 日歷Card y起點(diǎn)坐標(biāo)
*/
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
}
/**
* 繪制日歷文本
*
* @param canvas canvas
* @param calendar 日歷calendar
* @param x 日歷Card x起點(diǎn)坐標(biāo)
* @param y 日歷Card y起點(diǎn)坐標(biāo)
* @param hasScheme 是否是標(biāo)記的日期
* @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);
//繪制農(nóng)歷
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轉(zhuǎn)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"
效果預(yù)覽
高仿魅族日歷界面

魅族界面.png

魅族收縮.png
快速年月份選擇

月份界面.png
其它作者實(shí)現(xiàn)的幾個(gè)UI效果預(yù)覽,簡(jiǎn)單源碼都在demo可以看到
多彩風(fēng)格界面

多彩界面.png

多彩收縮.png
下標(biāo)風(fēng)格界面

下標(biāo)界面.png

下標(biāo)收縮.png
簡(jiǎn)單沒有農(nóng)歷界面

簡(jiǎn)單界面.png

簡(jiǎn)單收縮.png
更多參考用法移步APP Demo,里面作者實(shí)現(xiàn)了幾種類型的風(fēng)格,可以參考實(shí)現(xiàn)
項(xiàng)目開源地址
https://github.com/huanghaibin-dev/CalendarView