序
從這篇文章文章開始將會連載幾篇文章簡單描述下最近抽空針對RecyclerView的Adapter做的一個擴展庫。系列文章是對擴展庫逐步進行擴展的,有一定的先后關(guān)系,所以閱讀的話還是按照這個順序比較好。
這篇先不開始描述怎么去擴展,先說一下這個擴展庫將擁有什么樣的功能以及如何使用,也就是告訴讀者這些功能是不是符合口味,能不能吸引再往下讀。
該庫github地址:
https://github.com/yangxiaoweihn/RecyclerViewAdapter
該系列內(nèi)容已經(jīng)完結(jié),其他部分可以點擊下列閱讀:
RecyclerView-為Adapter添加頭部、尾部及事件響應(yīng)(第2篇)
RecyclerView-數(shù)據(jù)域的操作方法(第3篇)
RecyclerView-為Adapter增加滑動菜單支持(第4篇)
RecyclerView-為Adapter增加粘性頭部支持(第5篇)
本篇主要描述以下幾方面內(nèi)容:
- 擴展庫如何在項目中使用
- 擴展庫具有的功能
- 貼圖看看效果
- 擴展庫的api使用說明
擴展庫的使用
該庫已經(jīng)打包上傳到了maven、jcenter倉庫,使用Android Studio開發(fā)的同學(xué)肯定都知道怎么從倉庫引入庫的。
特殊注意:另外,這系列文章是針對源碼版本2.0描述的
compile 'ws.dyt.view:recyclerview-adapter-hf:2.0'
具有的功能
- 可以添加、刪除任意數(shù)量的頭部、尾部(就像ListView那樣)
- 可以添加系統(tǒng)頭部、尾部(數(shù)量和使用上做了限制,在使用上盡量不要去使用這部分),具體說明將會在之后的文章中進行闡述。
- 可以針對不同的item添加滑動菜單(目前只支持左滑、右滑),并且菜單定制性高
- 支持粘性視圖,同時支持滑動菜單
效果圖
在能讓讀者有足夠的好奇心讀以下的文章前,先貼幾張效果圖,拿效果圖最能說明該庫擁有的功能。







好了,效果圖已經(jīng)貼完,如果覺得這些功能不夠吸引的話,同學(xué)就可以止步了,因為只有得系列文章主要是為了闡述以上功能的開發(fā)過程及思路。
api使用說明
首先要說明一點:該api的使用與系統(tǒng)原生提供的有區(qū)別,不要思維定式。簡單說起來就是使用更簡單,大概姿勢如下:
1. 構(gòu)造(構(gòu)造方法)
2. 數(shù)據(jù)綁定
3. 多類型支持(設(shè)置布局,如果需要的話)
4. 事件
5. 添加頭部尾部控件
6. 橫跨列處理
7. 添加菜單
8. 添加粘性頭部
該庫主要實現(xiàn)了兩個具有一定功能的Adapter,命名為SuperAdapter、SuperPinnedAdapter。從實現(xiàn)上來講,SuperPinnedAdapter間接繼承自SuperAdapter,所以功能上就不言而喻了。
SuperAdapter具有添加頭部尾部、以及滑動菜單功能,而SuperPinnedAdapter在此基礎(chǔ)上增加了粘性視圖的支持。
通過構(gòu)造方法進行初始化(具體的參數(shù)說明請看注釋)
/**
* 調(diào)用該構(gòu)造方法時需要調(diào)用 {@link #getItemViewLayout(int)} 設(shè)置item布局
* @param context
* @param datas
*/
public SuperAdapter(Context context, List<T> datas) {
super(context, datas);
}
/**
* 調(diào)用該構(gòu)造方法時默認(rèn)數(shù)據(jù)項都采用 itemLayoutResId 布局,同樣可以調(diào)用 {@link #getItemViewLayout(int)} 重新設(shè)置item布局
* @param context
* @param datas
* @param itemLayoutResId
*/
public SuperAdapter(Context context, List<T> datas, @LayoutRes int itemLayoutResId) {
this(context, datas);
}
以上兩個構(gòu)造方法最大的區(qū)別是:用第一種方法構(gòu)造后需要調(diào)用getItemViewLayout()設(shè)置item的布局。用后一種的話已經(jīng)設(shè)置了item布局,不過這種方式是所有的item布局都是一樣的。
數(shù)據(jù)綁定
數(shù)據(jù)的綁定在原生里是onBindViewHolder(),而在這里,將該方法進行了屏蔽,而是用convert()方法(使用上與onBindViewHolder()一致,但是也更簡單),可以簡單的將他倆看成是對等的關(guān)系,但是事實上不是這樣的,具體的我將會在后續(xù)的文章中進行具體描述。
/**
* 綁定數(shù)據(jù)
* @param holder
* @param position 數(shù)據(jù)域從0開始,已經(jīng)除去頭部
*/
abstract
public void convert(BaseViewHolder holder, int position);
該方法的第一個參數(shù)該庫做了進一步封裝,具體來說就是整個庫里BaseViewHolder類無法被擴展,所有常用的操作方法已經(jīng)在該類中進行了封裝(后續(xù)版本在決定是否可以允許該類擴展),BaseViewHolder的功能將會在后面的文章進行描述。BaseViewHolder的鏈條操作:
//只是一個例子而已,旨在說明鏈條操作,不必注意實體類是什么
CourseResult.Course e = getItem(position).data;
holder.
setText(R.id.tv_name, e.name).
setText(R.id.tv_length, e.length);
多item支持
通過構(gòu)造方法已經(jīng)知道,用構(gòu)造方法是沒有辦法設(shè)置Adapter的多item樣式支持的。那么在該庫中,通過以下方法進行設(shè)置:
/**
* 提供item對應(yīng)的布局
*/
public int getItemViewLayout(int position) {}
事件
網(wǎng)上一大片文章都在講RecyclerView怎么設(shè)置item的點擊事件云云,事實上確實很簡單,RecyclerView暴露的方法就那么幾個,所以在這里事件是怎么加上去的也將在后續(xù)的文章中闡述,這里只需要知道該庫一定也提供了設(shè)置事件監(jiān)聽的方法。
對item的點擊事件支持以下兩種:
/**
* 點擊事件
*/
public interface OnItemClickListener {
void onItemClick(View itemView, int position);
}
/**
* 長按事件
*/
public interface OnItemLongClickListener {
void onItemLongClick(View itemView, int position);
}
設(shè)置監(jiān)聽器:
//設(shè)置點擊事件
adapter.setOnItemClickListener(new SuperAdapter.OnItemClickListener() {
@Override
public void onItemClick(View itemView, int position) {
}
});
//設(shè)置長按事件
adapter.setOnItemLongClickListener(new SuperAdapter.OnItemLongClickListener() {
@Override
public void onItemLongClick(View itemView, int position) {
}
});
添加頭部、尾部控件
原生RecyclerView并沒有提供像ListView中那樣可以隨意添加header和footer的api,但是在實際的場景中我們確實需要這樣的功能,那么該庫也一定提供了這樣的方法。
首先需要簡單說一下SuperAdapter數(shù)據(jù)域的構(gòu)成:
{
item_sys_header - item_header -
item_data -
item_footer - item_sys_footer
}
從上面的結(jié)構(gòu)中可以看到,大體分為3中(header部分、數(shù)據(jù)部分、footer部分),細(xì)分的話,頭部又分為系統(tǒng)header部分(item_sys_header)和用戶header部分(item_header),footer部分分為系統(tǒng)footer部分(item_footer)和用戶footer部分(item_sys_footer)。
我為什么要這么劃分呢,在實現(xiàn)上是有一些考慮的,頭部和尾部不要去污染數(shù)據(jù)部分(分離),這樣在擴展上更好一些。一般在使用時系統(tǒng)header和系統(tǒng)footer可以忽略,加這兩個的用途也是為了擴展用,比如在我的另外一個上拉加載庫中就用了系統(tǒng)footer。
主要提供了一下幾個api:
final
public void addHeaderView(View view);
final
public void addHeaderView(View view, boolean changeAllVisibleItems);
final
public void removeHeaderView(View view);
final
public void removeHeaderView(View view, boolean changeAllVisibleItems);
final
public void addFooterView(View view);
final
public void addFooterView(View view, boolean changeAllVisibleItems);
final
public void removeFooterView(View view);
final
public void removeFooterView(View view, boolean changeAllVisibleItems);
其中changeAllVisibleItems表示是否只刷新可見區(qū)域(為true時),否則只刷新當(dāng)前發(fā)生變化的item,默認(rèn)為false
橫跨列的api
在RecyclerView的布局管理器是GridLayoutManager或者StaggeredGridLayoutManager時,有些item需要橫跨所有列,這種情況下我們也提供了以下api去設(shè)置,默認(rèn)為false,表示保持管理器設(shè)置,為true時表示橫跨。
/**
* 設(shè)置是否橫跨
* @param position
* @return
*/
protected boolean isFullSpanWithItemView(int position) {
return false;
}
添加菜單及菜單事件
public List<MenuItem> onCreateMultiMenuItem(int viewType) {
List<MenuItem> mm = new ArrayList<>();
mm.add(new MenuItem(R.layout.menu_item_test_delete, MenuItem.EdgeTrack.RIGHT, 01));
mm.add(new MenuItem(R.layout.menu_item_test_mark, MenuItem.EdgeTrack.RIGHT, 02));
return mm;
}
@Override
public boolean isCloseOtherItemsWhenThisWillOpen() {
return true;}adapter.setOnItemMenuClickListener(new OnItemMenuClickListener() {
@Override
public void onMenuClick(SwipeLayout swipeItemView, View itemView, View menuView, int position, int menuId) {
if (menuId == 01) {
swipeItemView.closeMenuItem();
Log.d("DEBUG", "--menu: 刪除 -> position: " + position + " , menuId: " + menuId);
Toast.makeText(getContext(), "刪除", Toast.LENGTH_SHORT).show();
} else if (menuId == 02) {
Log.d("DEBUG", "--menu: 關(guān)注 -> position: " + position + " , menuId: " + menuId);
Toast.makeText(getContext(), "加關(guān)注", Toast.LENGTH_SHORT).show();
}
}
});
添加粘性頭部及數(shù)據(jù)綁定
注意粘性頭部的Adapter是PinnedAdapter.
@Override
public int getPinnedItemViewLayout() {
return R.layout.item_pinned;
}
@Override
public void convertPinnedHolder(BaseViewHolder holder, int position, int type) {
holder.setText(R.id.tv_text_pinned, getItem(position).data.title);
}
概括的介紹就到這里。