一配紫、介紹
MaterialCalendarView是一個日歷控件径密。
作者對它封裝的很深,如果你要加入自己的一些東西比較難躺孝,他給出的接口感覺太少了享扔,網(wǎng)上一些文章基本都是直接拉源碼下來修改的,個人不太喜歡那樣做植袍。所以自己閱讀源碼和框架惧眠,在他給出的接口上完成了自定義樣式,基本需要改的東西都可以實現(xiàn)了于个。先上一個效果圖氛魁。
主要分兩部分:
一個是添加了價格的文本顯示。
一個是添加了自定義的選中樣式。
二秀存、添加價格
切入點
首先框架并沒有提供設(shè)置每日的布局的地方捶码,所以直接用Xml來改變布局是行不通的。
然后通過閱讀介紹或链,他有提供一個名為DotSpan的類宙项,它的效果是在DayViewDecorator里面設(shè)置一個背景樣式,在文字下面加了兩個點株扛。顯然這就是作者留給我們的添加自定義樣式的地方。
我們就可以從這里入手汇荐,模仿這個文件來添加自定義樣式洞就。
實現(xiàn)
public class BackgroundSpan implements LineBackgroundSpan {
@Override
public void drawBackground(Canvas canvas, Paint paint,
int left, int right, int top, int baseline, int bottom,
CharSequence charSequence,
int start, int end, int lineNum) {
canvas.save();
canvas.drawColor(Color.parseColor("#ffd6ba"));
canvas.restore();
}
}
添加流程是:
-
設(shè)置裝飾器
calendarView.addDecorators(priceDecorator);
priceDecorator是一個實現(xiàn)DayViewDecorator的類。
-
在Decorator設(shè)置Span
@Override public void decorate(DayViewFacade view) { view.addSpan(new PriceSpan()); }
這里分為兩種情況:
-
需要添加的樣式是固定的掀淘。也就是和具體某一天無關(guān)旬蟋,只是這天需要加上這個標(biāo)簽,那么建議直接使用DayViewDecorator的方法
@Override public boolean shouldDecorate(CalendarDay day) { return true; }
利用這個方法作為判斷條件革娄,需要的地方繪制上即可倾贰。
-
需要根據(jù)不同的日子顯示不同的數(shù)據(jù)的,即是我上圖的需求一樣拦惋。那么就按這個思路來:
因為在繪制的方法drawBackground里面 拿不到Y(jié)ear和Month匆浙,這就導(dǎo)致了無法和數(shù)據(jù)進行關(guān)聯(lián),我的解決方案是利用控件的OnMonthChangedListener監(jiān)聽厕妖,在他翻頁結(jié)束后獲取當(dāng)前頁的year和month首尼,根據(jù)兩個再加上傳遞的Day參數(shù)來取數(shù)據(jù)。
注意:這個方法會有一個弊端言秸,就是他是一個ViewPager的setOnPageChangeListener软能,但是他的回調(diào)只給了onPageSelected的回調(diào),也就是說它無法在一開始拖動的時候就改變year和month举畸,所以2榕拧!抄沮!你在拖動至一半的時候看到兩邊的數(shù)據(jù)會是一樣的0虾恕! 這就是我這個方法的坑點合是,但是我還沒找到方法解決了罪,我只能將比較顯眼的背景色部分分離出來 按照第一種情況來做,這樣一般情況看不出來問題聪全。
貼一個效果圖感受一下
可以看見價格兩邊是一樣的泊藕,但是背景色被我處理了不會出現(xiàn)這種情況,還是可以接受的。
Span
public class PriceSpan implements LineBackgroundSpan {
private String format = "%s-%s-%s";
private String priceFormat = "$%s";
private String singleDayFormat = "0%s";
private int height;
private int width;
private int dayTextSize;
private int priceTextSize;
private int marginOne;
private int marginTwo;
// 用來讓選中的那個日期變白色字體
private boolean keepWhite;
PriceSpan() {
height = Utils.dip2px(GotoBusApplication.getAppContext(), 54);
width = Utils.dip2px(GotoBusApplication.getAppContext(), 40);
dayTextSize = UIUtil.sp2px(GotoBusApplication.getAppContext(), 17);
priceTextSize = UIUtil.sp2px(GotoBusApplication.getAppContext(), 11);
marginOne = Utils.dip2px(GotoBusApplication.getAppContext(), 6);
marginTwo = Utils.dip2px(GotoBusApplication.getAppContext(), 10);
}
@Override
public void drawBackground(Canvas canvas, Paint paint,
int left, int right, int top, int baseline, int bottom,
CharSequence charSequence,
int start, int end, int lineNum) {
canvas.save();
int oldColor = paint.getColor();
float oldTextSize = paint.getTextSize();
keepWhite = false;
int Y = (height - bottom) / 2;
canvas.translate(0, -Y);
String day = charSequence.toString();
Date date = null;
try {
date = DateUtils.sdf3.parse(String.format(format, year, month, day));
if (dates != null && dates.size() > 0) {
if (dates.get(0).getDate().getTime() == date.getTime() ||
dates.get(dates.size() - 1).getDate().getTime() == date.getTime()) {
keepWhite = true;
}
}
} catch (ParseException e) {
e.printStackTrace();
}
canvas.translate(0, Y);
// 繪制日期
paint.setTextSize(dayTextSize);
Rect rectDay = new Rect();
paint.getTextBounds(day, 0, charSequence.length(), rectDay);
// 判斷日期在當(dāng)前時間之前就變灰色
if (keepWhite) {
paint.setColor(Color.WHITE);
} else if (currentDate.before(date)) {
paint.setColor(Color.BLACK);
} else {
paint.setColor(Color.GRAY);
}
canvas.drawText(day, (width - rectDay.width()) / 2, marginOne, paint);
// 繪制價格
if (hasPrice) {
//個位的日期前面加上一個0
if (day.length() == 1) {
day = String.format(singleDayFormat, day);
}
String currentDay = String.format(format, year, month, day);
String price = priceMap.get(currentDay);
if (price != null) {
String priceString = String.format(priceFormat, price);
if (keepWhite) {
paint.setColor(Color.WHITE);
} else if (price.equals(lowestData)) {
paint.setColor(Color.parseColor("#34b03d"));
} else {
paint.setColor(Color.parseColor("#999999"));
}
paint.setTextSize(priceTextSize);
Rect rect = new Rect();
paint.getTextBounds(priceString, 0, priceString.length(), rect);
canvas.drawText(priceString, (width - rect.width()) / 2,
rectDay.height() + marginOne + marginTwo, paint);
}
}
paint.setColor(oldColor);
paint.setTextSize(oldTextSize);
canvas.restore();
}
}
Canvas canvas:畫布 通過這個來繪制自己的樣式娃圆。但是要注意它是已經(jīng)移動過的玫锋,移動的距離可以通過(height (整個item的高度)- bottom(參數(shù))) / 2來計算;
paint:注意保存之前的屬性。不然會引起繪制位置不準(zhǔn)確讼呢。
int left, int right, int top, int baseline, int bottom 這些參數(shù)都是框架內(nèi)繪制日期的位置參數(shù)撩鹿。canvas位置就是移動到了這里,所以left和top都是0悦屏,right就是整體的寬度节沦,bottom就是Day日期文本的高度。
CharSequence charSequence:當(dāng)前Day日期础爬。(只有Day 沒有year和month甫贯,我覺得這里比較坑。)
54dp是我的item高度 40是寬度看蚜。
這段代碼是包含了一個日期的繪制叫搁,因為它框架內(nèi)的日期是居中的,導(dǎo)致留給我顯示價格的地方太短了 不美觀供炎,所以我把原來的文本設(shè)置為透明色(calendarView.setDateTextAppearance(R.style.calendar_date_text);)隱藏了起來渴逻,然后自己在合適的位置繪制日期。這么做就會讓框架原來的一些效果消失(例如之前的日期變灰色等)音诫,所以還需要另外自己處理這些問題惨奕。
OK 價格部分就介紹完了。
二纽竣、自定義背景色
首先自定義背景色有兩種方法:
- 就是固定的選中背景色墓贿,也就是大家都一樣,沒有什么頭尾的蜓氨。
- 就是我這種設(shè)計的背景色聋袋,頭尾不一樣的樣式。
第一種
建議就使用
@Override
public void decorate(DayViewFacade view) {
view.setSelectionDrawable(drawable);
}
來設(shè)置一個Drawable來替換掉原來的背景圈穴吹,其他的部分框架已經(jīng)幫你處理好了幽勒。
第二種
就比較麻煩了,
首先你需要將原本框架的背景色那個圓的去掉港令,就是按第一種方法給它設(shè)置一個透明的drawable啥容。
-
為了避免上文提到的拖動坑的情況,我們要寫多個文件來達到效果顷霹。
這是我左邊開始的背景文件咪惠,以此為參考。
/** * Created by Vito on ${date} */ public class LeftSelectedDecorator implements DayViewDecorator, OnDateSelectedListener, OnRangeSelectedListener { private List<CalendarDay> dates; public LeftSelectedDecorator(List<CalendarDay> dates) { if (dates != null && dates.size() > 0) { this.dates = dates; } else { this.dates = new ArrayList<>(); } } @Override public boolean shouldDecorate(CalendarDay day) { if (dates.size() > 1) { if (day.getDate().getTime() == dates.get(0).getDate().getTime()) { return true; } else { return false; } } else { return false; } } @Override public void decorate(DayViewFacade view) { view.addSpan(new BackgroundSpan()); } @Override public void onRangeSelected(@NonNull MaterialCalendarView widget, @NonNull List<CalendarDay> dates) { this.dates = dates; } @Override public void onDateSelected(@NonNull MaterialCalendarView widget, @NonNull CalendarDay date, boolean selected) { dates.clear(); if (selected) { dates.add(date); } } public class BackgroundSpan implements LineBackgroundSpan { private int round; private int height; private int width; BackgroundSpan() { height = Utils.dip2px(GotoBusApplication.getAppContext(), 54); width = Utils.dip2px(GotoBusApplication.getAppContext(), 40); round = Utils.dip2px(GotoBusApplication.getAppContext(), 6); } @Override public void drawBackground(Canvas canvas, Paint paint, int left, int right, int top, int baseline, int bottom, CharSequence charSequence, int start, int end, int lineNum) { canvas.save(); int oldColor = paint.getColor(); float oldTextSize = paint.getTextSize(); canvas.translate(0, -(height - bottom) / 2); paint.setColor(Color.parseColor("#ff8945")); RectF rect = new RectF(0, 0, width + round, height); canvas.drawRoundRect(rect, round, round, paint); paint.setColor(oldColor); paint.setTextSize(oldTextSize); canvas.restore(); } } }
注意:多個Decorator添加要注意順序淋淀,會蓋住遥昧,一般是在文本最后。
calendarView.addDecorators(leftSelectedDecorator, rightSelectedDecorator,
singleSelectedDecorator, selectedDecorator, priceDecorator);
注意:監(jiān)聽需要分發(fā)一下
calendarView.setOnRangeSelectedListener(new OnRangeSelectedListener() {
@Override
public void onRangeSelected(@NonNull MaterialCalendarView widget, @NonNull List<CalendarDay> dates) {
leftSelectedDecorator.onRangeSelected(widget, dates);
rightSelectedDecorator.onRangeSelected(widget, dates);
singleSelectedDecorator.onRangeSelected(widget, dates);
selectedDecorator.onRangeSelected(widget, dates);
priceDecorator.onRangeSelected(widget, dates);
}
});
calendarView.setOnDateChangedListener(new OnDateSelectedListener() {
@Override
public void onDateSelected(@NonNull MaterialCalendarView widget, @NonNull CalendarDay date, boolean selected) {
leftSelectedDecorator.onDateSelected(widget, date, selected);
rightSelectedDecorator.onDateSelected(widget, date, selected);
singleSelectedDecorator.onDateSelected(widget, date, selected);
selectedDecorator.onDateSelected(widget, date, selected);
priceDecorator.onDateSelected(widget, date, selected);
}
});
四、完工
這里就是全部內(nèi)容了炭臭,覺得有幫助的話點個贊叭永脓!什么問題的話可以直接評論說啦!如果有更好的解決方案也希望可以教教我鞋仍。特別是可以完美的填掉我那個坑的方案常摧!