聽過PullToRefreshListView,聽過PinnedSectionListView,那你應該沒聽過CalendarListView,什麼是CalendarListView呢,ListView和Calendar扯上什麼關係呢,我們先來看下Demo(動畫效果會稍微有點卡頓,真實效果會比較流暢,大家可以到我GitHub下載apk自己試用一下,效果還不錯!)。
CalendarListView 是一個ListView 和 CalendarView 結合並互相聯動的控件,日曆可以伸縮擴展,列表可以上拉下沉, 日曆的選擇會讓ListView 滑動到指定的位置,ListView的滑動同時也會帶動日曆滑到指定位置並能同時自動切換月份。如果我們的應用涉及到聊天記錄、筆記、訂單記錄、天氣、日報等和時間關係比較緊的業務場景,這樣的控件要比簡單的ListView 來得更清晰一些,也更炫一些。如果你喜歡,可以先收藏很多業務場景都可以使用。
GitHub:https://github.com/Kelin-Hong/CalendarListView
功能簡介:
可以參照上面的動畫,我安裝上面演示的順序說明:
1、CalendarListView 的上部分是常規的日曆模塊,在日曆不收縮的情況下上下滑動可以切換月份
2、在日曆不收縮的情況,選擇日曆某一天,ListView的滑到指定日期的那一條。
3、在日曆不收縮的情況,選擇日曆某一天,選完之後,把ListView往上拉,這時候會根據日曆選中日期(紅色框)的高度,計算出日曆的滑動速率,從而使整體滑到頂部的時候,日曆日期選中的那一行是可見的。
4、在日曆收縮的情況下,按住日曆往下拉,這時候和上面一樣經過計算,使控件能夠平滑的展開。
5、在日曆執行展開或者收縮過程中,用手在拖動中,如果拖動的距離超過一半放手了,會有動畫執行剩下的下滑或者上拉操作,如果拖動沒有超過一半,會自動回到原來的位置。
6、在日曆收縮的情況下,滑動ListView,這時候日期當前ListView的section的日期變化了,那麼日曆會自動選中當前pin住的那個header的日期,ListView上下滑動都會牽動日曆日期的變更(日曆會上下滑動同時選中header的日期)
7、ListView 往下滑,到底的時候會自動觸發LoadMore操作,當從1月份滑到二月份的時候,日曆會自動切換2月份同時選中指定的日期。
8、ListView 往上滑,到最頂部時候會自動觸發Refresh操作,當從1月份滑到去年12月份的時候,日曆會自動切換到去年12月份同時選中指定的日期。
9、ListView 快速滑動試,日曆跟隨的日期仍能不會錯
10、在日曆收縮的情況,選擇日曆某一天,ListView的依然滑到指定日期的那一條。
如何使用
compile 'com.kelin.mvvmlight:library:1.0.0'
CalendarListView 接口的設計使得用戶完全可以定製想要的UI和各種響應的事件的支持
1、自定義CalendarView的樣式(在小格子裏添加價格,tag,圖標等)
//繼承BaseCalendarItemModel添加你想要的額外的字段,比較價格,是否收藏,數量等
public class CustomCalendarItemModel extends BaseCalendarItemModel{
//這一天有多少條數據
private int count;
//是否收藏(如Demo 日曆上有沒有愛心)
private boolean isFav;
//get set
...
...
}
// 繼承BaseCalendarItemAdapter<T> (T 爲你自定義的Model extendsBaseCalendarItemModel),
// 重寫 getView方法自定義CalendarView Item 的樣式和數據
public class CalendarItemAdapter extends BaseCalendarItemAdapter<CustomCalendarItemModel>{
//date 是時間,樣式“yyyy-MM-dd”
@Override
public View getView(String date, CustomCalendarItemModel model, View convertView, ViewGroup parent) {
//也可以從dayModelList 根據date獲取指定時間的model(dayModelList是基類的變量) CustomCalendarItemModel model = dayModelList.get(date);
....
ViewGroup view = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.custom_calendar_item, null);
TextView dayNum = (TextView) view.findViewById(R.id.day_num);
dayNum.setText(model.getDayNumber());
....
//從model裏面獲取數據自定義想要的UI
....
....
}
}
注:如果不需要再日曆頁面添加自定義的元素,也可以直接使用BaseCalendarItemAdapter ,這樣日曆的視圖只會有日期,依然是可用的。
public class ListItemAdapter extends BaseCalendarListAdapter<ListModel> {
//date 是時間,樣式“yyyy-MM-dd”
@Override
public View getSectionHeaderView(String date, View convertView, ViewGroup parent) {
List<ListModel> modelList = dateDataMap.get(date);
.....
.....//根據數據模型自定義ListView SectionHeader的樣式
.....
}
//date 是時間,樣式“yyyy-MM-dd”
@Override
public View getItemView(ListModel model,String date, int pos, View convertView, ViewGroup parent) {
//通過基類BaseCalendarListAdapter的成員變量dateDataMap可以獲取當前date的包含的數據列表
//List<ListModel> modelList = dateDataMap.get(date);
//model = modelList.get(pos) 也可以獲取model
.....
.....//根據數據模型model自定義ListView Item的樣式
.....
}
}
3、初始化CalendarListView 並且設置CalendarItemAdapter和ListItemAdapter
<com.kelin.calendarlistview.library.calendar.CalendarListView
android:id="@+id/calendar_listview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.kelin.calendarlistview.library.calendar.CalendarListView>
//在onCreate中分別創建兩個Adapter的實例,並且設置到CalendarListView裏面
@Override
protected void onCreate(Bundle savedInstanceState) {
//獲取calendarListView
calendarListView = (CalendarListView) findViewById(R.id.calendar_listview);
//聲明CalendarView和ListView的Adapter,分別爲上面1、2步自定義的樣式的Adapter
listItemAdapter = new ListItemAdapter(this);
calendarItemAdapter = new CalendarItemAdapter(this);
//給calendarListView設置Adapter
calendarListView.setCalendarListViewAdapter(calendarItemAdapter, listItemAdapter);
}
4、去服務器獲取日曆和列表的數據(建議接口按月份來)獲取每個月份的數據,在獲取完數據更新日曆和列表
- 對於CalendarView的數據更新
private void onCalendarDataLoadFinish(List<Data> datas){
....
....
//calendarItemAdapter.getDayModelList()可以獲取當前月份的所有數據列表
//它是一個TreeMap<String, T>,key是“yyyy-MM-dd”,value 是當天的數據模型
TreeMap<String, CustomCalendarItemModel> dateMap=calendarItemAdapter.getDayModelList();
....
//獲取指定日期的Model,date的格式是yyyy-MM-dd
CustomCalendarItemModel customCalendarItemModel = dateMap.get(date);
//更新數據模型的數據
customCalendarItemModel.setXXX(data.getXXX());
....
....
//通知日曆更新UI
calendarItemAdapter.notifyDataSetChanged();
}
- 對於ListView的數據更新
//建議聲明一個TreeMap<String, List<ListModel>>的成員變量用來保持每一天下面的數據列表
//key:date "yyyy-mm-dd" format.
private TreeMap<String, List<ListModel>> listTreeMap = new TreeMap<>();
private void onListDataLoadFinish(List<Data> datas){
....
....
for(Data item:datas) {
//獲取數據的日期
String day=item.getDate();
//給listTreeMap 添加數據
if (listTreeMap.get(day) != null) {
List<NewsService.News.StoriesBean> list = listTreeMap.get(day);
list.add(i);
} else {
List<NewsService.News.StoriesBean> list = new ArrayList<NewsService.News.StoriesBean>();
list.add(i);
listTreeMap.put(day, list);
}
}
....
....
//更新數據,通知更新UI
listItemAdapter.setDateDataMap(listTreeMap);
listItemAdapter.notifyDataSetChanged();
}
5、CalendarView的事件支持
日期選擇
calendarListView.setOnCalendarViewItemClickListener(new CalendarListView.OnCalendarViewItemClickListener() {
//具體參數看註釋,寫得比較詳細
@Override
public void onDateSelected(View View, String selectedDate, int listSection) {
//do something....
}
});
月份改變calendarListView.setOnMonthChangedListener(new CalendarListView.OnMonthChangedListener() {
@Override
public void onMonthChanged(String yearMonth) {
//yearMonth:"yyyy-MM-dd"
}
});
下拉刷新,上拉加載更多
calendarListView.setOnListPullListener(new CalendarListView.onListPullListener() {
@Override
public void onRefresh() {
}
@Override
public void onLoadMore() {
}
});
6、CalendarView的選中框樣式顏色、上方的week bar 的樣式都是支持自定義的。
備註
1、控件部分交互有些小複雜,可能存在一些Bug,歡迎issue和PR!
2、源碼涉及較多事件分發的處理,如果你有看過我的另一篇文章《圖解Android事件分發機制》,那麼源碼應該是比較好的實踐,可以去讀一下。
3、任何控件上的問題或者使用上的問題,可以給我留言或私信。
4、最後,喜歡可以收藏哦!O(∩_∩)O~~
原文鏈接:http://www.jianshu.com/p/ca2af05b3a53#
著作權歸作者所有,轉載請聯繫作者獲得授權,並標註“簡書作者”。