概述
之前寫了兩篇文章簡要的介紹了(CalendarSelector)庫的使用方法和基本的實現(xiàn)原理辽话,這篇文章呢主要來實現(xiàn)一個仿iOS日歷的顯示功能
CalendarSelector庫簡介
(CalendarSelector)庫可以用來做日歷的顯示和選擇功能,因為使用的是View組合的方式來實現(xiàn)的,而不是使用Canvas來繪制捉捅,所以自定義起來比較簡單
仿iOS顯示一年的日歷
在蘋果手機上看到下面日歷顯示的效果比較好,自己也想在Android上實現(xiàn)一下:)
分析了下虽风,要想實現(xiàn)這種效果棒口,主要要解決三個顯示相關(guān)的問題
- 月份文字的顯示位置(包括下面的那條橫線)
- 行中間的那幾條橫線的顯示
- 最后一行橫線的顯示
接下來集中來解決上面提出的幾個問題
月份文字的顯示位置(包括下面的那條橫線)
經(jīng)過分析可以知道,月份文字的顯示位置其實就是該月第一天的起始位置辜膝,然后根據(jù)這個位置信息動態(tài)的計算下坐標(biāo)无牵,scrollTo(x, y)到相應(yīng)的位置就行了(不采用改動layout的方式主要是為了性能考慮,調(diào)起requestLayout流程還是很耗時間的)
final int firstdayOfWeekPosInMonth = scMonth.getFirstdayOfWeekPosInMonth();
// wait for MonthView measure finish
holder.monthView.post(new Runnable() {
@Override
public void run() {
ValueAnimator lineAnimator = ValueAnimator.ofInt(0, -(firstdayOfWeekPosInMonth - 1) * holder.monthView.getDayWidth());
lineAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int scrollX = (int) animation.getAnimatedValue();
holder.flScrollLine.scrollTo(scrollX , 0);
}
});
ValueAnimator monthAnimator = ValueAnimator.ofInt(0, -(firstdayOfWeekPosInMonth - 1) * holder.monthView.getDayWidth()
- (holder.monthView.getDayWidth() / 2 - holder.tvMonthTitle.getWidth() / 2));
monthAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int scrollX = (int) animation.getAnimatedValue();
holder.flScrollMonth.scrollTo(scrollX , 0);
}
});
AnimatorSet animationSet = new AnimatorSet();
animationSet.play(monthAnimator).with(lineAnimator);
animationSet.setInterpolator(new AccelerateDecelerateInterpolator());
animationSet.setDuration(500);
animationSet.start();
int dayCount = holder.monthView.getCurrentMonthLastRowDayCount();
View decorView = holder.monthView.getLastHorizontalDecor();
if(decorView != null)
decorView.scrollTo((7 - dayCount)*holder.monthView.getDayWidth(), 0);
}
});
自己加了一個動畫厂抖,主要是想試一下效果:)
行中間的那幾條橫線的顯示
看過(CalendarSelector)文檔的都知道茎毁,庫本身是支持添加行和列裝飾的,在這里的話只需要過濾下第一行和最后一行忱辅,不進行設(shè)置
@Override
public Decor inflateHorizontalDecor(ViewGroup container, int row, int totalRow) {
return new Decor(mLayoutInflater.inflate(R.layout.view_horizontal_decor, container, false));
}
@Override
public boolean isShowHorizontalDecor(int row, int realRowCount) {
if(row == 0 || row == realRowCount) return false;
return super.isShowHorizontalDecor(row, realRowCount);
}
最后一行橫線的顯示
因為最后一行橫線顯示的位置也需要跟隨天數(shù)七蜘,所以需要特殊處理一下,考慮到MonthView在RecyclerView中使用的情況墙懂,需要處理好復(fù)用還原的問題橡卤,所以添加了一個自定義屬性來標(biāo)識是否需要reset
int dayCount = holder.monthView.getCurrentMonthLastRowDayCount();
View decorView = holder.monthView.getLastHorizontalDecor();
if(decorView != null)
decorView.scrollTo((7 - dayCount)*holder.monthView.getDayWidth(), 0);
<attr name="sc_should_reset_decor" format="boolean"/>
if(shouldResetDecor){
for (int i = 0; i < horizontalDecors.size(); i++) {
DayViewInflater.Decor decor = horizontalDecors.get(i);
if(decor != null && decor.getDecorView() != null)
decor.getDecorView().scrollTo(0, 0);
}
}
經(jīng)過前面三步的實現(xiàn),跟蘋果的效果基本上相同了损搬,具體實現(xiàn)可以查看(AppleCalendarActivity)示例代碼
總結(jié)
可以發(fā)現(xiàn)使用(CalendarSelector)庫來實現(xiàn)一些自定義效果還是比較方便的碧库,自己也會盡可能的把一些有用的數(shù)據(jù)暴露出來。自己接下來會著重解決配合RecyclerView使用時遇到的性能問題(創(chuàng)建item view時會出現(xiàn)比較明顯的掉幀現(xiàn)象)