CalendarListView 日曆列表

聽過PullToRefreshListView,聽過PinnedSectionListView,那你應該沒聽過CalendarListView,什麼是CalendarListView呢,ListView和Calendar扯上什麼關係呢,我們先來看下Demo(動畫效果會稍微有點卡頓,真實效果會比較流暢,大家可以到我GitHub下載apk自己試用一下,效果還不錯!)。


CalendarListView Demo

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 ,這樣日曆的視圖只會有日期,依然是可用的。
2、自定義ListView的樣式,和傳統的BaseAdapter 差不多,重寫getSectionHeaderView自定義SectionHeader的樣式,重寫getItemView自定義每個Item的樣式。
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~~



文/Kelin(簡書作者)
原文鏈接:http://www.jianshu.com/p/ca2af05b3a53#
著作權歸作者所有,轉載請聯繫作者獲得授權,並標註“簡書作者”。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章