BRAVH是一個(gè)recyclerView的adapter葬燎,能夠快速適配多種類型adapter谱净,可定制,用的人挺多裕寨,下面我們就來分析分析他的源碼,模擬來寫一個(gè)我們的adapter驾窟。
我們將recyclerView的adapter與自定義viewholder聯(lián)系在一起绅络,使用了BaseQuickAdapter<T, K extends BaseViewHolder>來作為recycler.adapter
先看BRAVH的BaseViewHolder類
BaseViewHolder extends RecyclerView.ViewHolder
繼承自ViewHolder,里面setXXX方法全是由itemview里面的view調(diào)用方法實(shí)現(xiàn)
存放了一個(gè)SparseArray<View> views成員變量用來初始化或者第一次遍歷存放引用衷恭,添加快捷操作随珠,省去下一次findview的時(shí)間
接下來看BaseQuickAdapter類
BaseQuickAdapter<T, K extends BaseViewHolder> extends RecyclerView.Adapter<K>
將K泛型傳入給RecyclerView.Adapter作為viewholder
T泛型分析:
傳入的數(shù)據(jù)集List<T>的類型,用來綁定數(shù)據(jù)
自定義Adapter,Viewholder
我們也來模擬一個(gè)adapter類型,使用自定義繼承viewHolder的MyViewHolder作為Viewholder
public class BackQuickAdapter<I,VH extends MyViewHolder> extends RecyclerView.Adapter<VH> {
private List<String> datas;
public BackQuickAdapter(List<String> datas) {
this.datas = datas;
}
@Override
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list,parent,false);
//實(shí)例化VH對(duì)象
return createViewHolder(view);
}
@Override
public void onBindViewHolder(VH holder, int position) {
View contentView = holder.itemView;
((TextView)contentView.findViewById(R.id.recycler_list_txt)).setText(datas.get(position));
//do something about contentView
}
@Override
public int getItemCount() {
return datas == null ? 0 : datas.size();
}
}
這樣我們就有了一個(gè)adapter显沈,里面的Viewholder由外部傳進(jìn)來,我們可以繼承該Viewholder自己做快捷操作遂唧,讓外部繼承實(shí)現(xiàn)MyViewholder邏輯盖彭,同BaseViewHolder,他也只是對(duì)itemview引用設(shè)置子View參數(shù)隧熙,這部分基本忽略贞盯。我們看onCreateViewHolder->VH createViewHolder(View view)這個(gè)方法躏敢,這是一個(gè)泛型類的實(shí)例化讥脐,這個(gè)直接上代碼見git旬渠。
給itemView添加加載動(dòng)畫
onViewAttachedToWindow(VH holder)方法:
每次Viewholder添加到window的時(shí)候contentView開始動(dòng)畫可以制作item加載效果
想要控制只讓itemView進(jìn)行一次動(dòng)畫,BRAVH里面設(shè)置了一個(gè)標(biāo)志位更哄,我們也寫一個(gè)AnimOnce來做這個(gè)標(biāo)志位成翩,每次加載的時(shí)候得到viewholder的位置,并與上一次的加載過的位置比較术羔,如果小级历,代表當(dāng)前位置的contentview是新的,需要開啟動(dòng)畫,否則如果AnimOnce只要一次粤策,不開啟動(dòng)畫叮盘,因?yàn)閯?dòng)畫已經(jīng)之前被加載過,我們可以這樣實(shí)現(xiàn):
/**
* 是否只需要一次item加載動(dòng)畫
*/
private boolean AnimOnce = true;
/**
* 最新加載過動(dòng)畫的item的位置柔吼,用于比較下一次item的位置判斷是否要加載
*/
private int vaildPos = 0;
@Override
public void onViewAttachedToWindow(VH holder) {
int currentPos = holder.getAdapterPosition();
if(AnimOnce)
if(currentPos > vaildPos){
animateView(holder.itemView);
vaildPos = currentPos;
}
else{
animateView(holder.itemView);
}
super.onViewAttachedToWindow(holder);
}
private void animateView(View root){
root.setAlpha(0.3f);
root.animate().alpha(1).setDuration(2500).start();
}
public void setAnimOnce(boolean animOnce) {
AnimOnce = animOnce;
}
這樣萍膛,就能添加我們的itemview動(dòng)畫,如果需要外部定制嚷堡,我們可以修改我們的animateView(View root)方法蝗罗,給里面添加一個(gè)animation動(dòng)畫,并且提供外部接口蝌戒,比如:
private Animation animation = null;
public void setItemAnimation(Animation animation) {
this.animation = animation;
}
private void animateView(View root){
if(null != animation)
{
root.startAnimation(animation);
}
}
關(guān)于動(dòng)畫串塑,可以使用animator或者animation都可以的北苟,只要定制animateView方法
添加頭部尾部空數(shù)據(jù)的布局
我們看BRAVH如何實(shí)現(xiàn)妆档,
- 添加header,footer,loading的view
- GetItemCount需要返回的數(shù)據(jù)量為headercount + datas.size + footercount + loadingcount
- GetItemType如果position < headercount须板,返回頭布局類型甜奄,得到普通布局的normal_position = position - headercount如果normal_position < datas.size [List數(shù)據(jù)集],返回普通列表類型,否則代表有尾布局footer
下面我們也來模擬一個(gè)頭部尾部布局~
寫一個(gè)方法來添加頭部尾部視圖
private int headerLayout;
private int footerLayout;
private boolean hasHeader = false;
private boolean hasFooter = false;
//added first before call setAdapter
public void addHeaderView(@LayoutRes int headerLayout){
this.headerLayout = headerLayout;
hasHeader = true;
}
//added first before call setAdapter
public void addFooterView(@LayoutRes int footerLayout){
this.footerLayout = footerLayout;
hasFooter = true;
}
GetItemType返回對(duì)應(yīng)Type
@Override
public int getItemCount() {
return datas == null ? 0 : datas.size() + (hasFooter ? 1 : 0) + (hasHeader ? 1 : 0);
}
private final static int ITEM_TYPE_HEADER = -1;
private final static int ITEM_TYPE_NORMAL = 0;
private final static int ITEM_TYPE_FOOTER = 1;
@Override
public int getItemViewType(int position) {
int datasize = (datas == null ? 0 : datas.size());
int headerCount = hasHeader ? 1 : 0;
if(position < headerCount)
return ITEM_TYPE_HEADER;
int realIndex = position - headerCount;
if(realIndex < datasize){
return ITEM_TYPE_NORMAL;
}
else{
return ITEM_TYPE_FOOTER;
}
}
根據(jù)對(duì)于Type構(gòu)造Viewholder
@Override
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
View view = null;
switch (viewType)
{
case ITEM_TYPE_HEADER:
view = LayoutInflater.from(parent.getContext()).inflate(headerLayout, parent, false);
break;
case ITEM_TYPE_FOOTER:
view = LayoutInflater.from(parent.getContext()).inflate(footerLayout, parent, false);
break;
default:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list, parent, false);
}
//實(shí)例化VH對(duì)象
return createViewHolder(view);
}
根據(jù)position位置來綁定viewholder數(shù)據(jù)
@Override
public void onBindViewHolder(VH holder, int position) {
if(position < (hasHeader ? 1 : 0))
{
// this is header view
return ;
}
int realDataPos = adjustPositionByType(position);
if(realDataPos < datas.size())
{
View contentView = holder.itemView;
((TextView)contentView.findViewById(R.id.recycler_list_txt)).setText(datas.get(realDataPos));
}
else{
//this is footer View
}
}
這樣我們的頭部尾部布局就添加好了勺卢,添加loading布局與空布局也是一個(gè)道理,只是多加載了一種類型而已
加載更多的實(shí)現(xiàn)
這是在OnBindViewHolder->position判斷位置
如果position已經(jīng)在最后的位置唐全,那么觸發(fā)加載更多
下面我們可以寫一個(gè)加載更多的方法:
private void autoLoadMore(int position) {
if(position == getItemCount() -1)
{
Log.i("position","current end is "+String.valueOf(position));
//trigger loading more
}
}
@Override
public int getItemCount() {
return datas == null ? 0 : datas.size() + (hasFooter ? 1 : 0) + (hasHeader ? 1 : 0);
}
實(shí)現(xiàn)拖拽延届,滑動(dòng)刪除
BRAVH是怎么實(shí)現(xiàn)呢?官方這樣使用:
ItemDragAndSwipeCallback itemDragAndSwipeCallback = new ItemDragAndSwipeCallback(mAdapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemDragAndSwipeCallback);
itemTouchHelper.attachToRecyclerView(mRecyclerView);
// 開啟拖拽
mAdapter.enableDragItem(itemTouchHelper, R.id.textView, true);
mAdapter.setOnItemDragListener(onItemDragListener);
// 開啟滑動(dòng)刪除
mAdapter.enableSwipeItem();
mAdapter.setOnItemSwipeListener(onItemSwipeListener);
我們可以看到使用的類是ItemDragAndSwipeCallback 希停,這里面需要傳入adapter需要BaseItemDraggableAdapter類型阿弃,我們進(jìn)入ItemDragAndSwipeCallback 發(fā)現(xiàn)其實(shí)只是BaseItemDraggableAdapter回調(diào)用,其實(shí)本身并沒有用到任何BaseItemDraggableAdapter屬性呵恢。所以可以做出一個(gè)提取的過程声离,把傳入類型BaseItemDraggableAdapter修改成interface,只要RecyclerAdapter實(shí)現(xiàn)這個(gè)接口就可以了垃它,這樣不必非要傳入BaseItemDraggableAdapter類型。
這部分也可以直接用原生ItemTouchHelper陕习,復(fù)寫onMove實(shí)現(xiàn)item交換嫁审,onSwiped實(shí)現(xiàn)Item刪除
我們開始寫交換邏輯:
- 首先剔除header視圖的位置獲得在datas數(shù)據(jù)集中的位置realpos
- 交換數(shù)據(jù)集中的realpos位置數(shù)據(jù)
- Notifydatachanged
或許我們可以這樣實(shí)現(xiàn)
@Override
public void onItemDragMoving(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
//change item position
int from = getViewHolderPosition(source);
int to = getViewHolderPosition(target);
if (inRange(from) && inRange(to)) {
if (from < to) {
for (int i = from; i < to; i++) {
Collections.swap(datas, i, i + 1);
}
} else {
for (int i = from; i > to; i--) {
Collections.swap(datas, i, i - 1);
}
}
notifyItemMoved(source.getAdapterPosition(), target.getAdapterPosition());
}
}
public int getViewHolderPosition(RecyclerView.ViewHolder viewHolder) {
return viewHolder.getAdapterPosition() - (hasHeader ? 1 : 0);
}
private boolean inRange(int position) {
return position >= 0 && position < datas.size();
}
下面我們實(shí)現(xiàn)刪除邏輯:
- 首先剔除header視圖的位置獲得在datas數(shù)據(jù)集中的位置realpos
- 刪除數(shù)據(jù)集中的realpos位置數(shù)據(jù)
- NotifyItemRemoved
@Override
public void onItemSwiped(RecyclerView.ViewHolder viewHolder) {
//notify item removed
int position = getViewHolderPosition(viewHolder);
if(position >= 0 && position < datas.size()) {
datas.remove(position);
notifyItemRemoved(getPositionInSets(position));
}
}
public int getPositionInSets(int position) {
return position + (hasHeader ? 1 : 0);
}
自定義使用不同的Item類型
現(xiàn)在默認(rèn)item類型有header眷蜓,footer白魂,loading背传,empty梳星,default。如果想要自定義類型痒蓬,那么我們可以修改自定義的adapter,在getItemType返回default類型的時(shí)候双揪,使用抽象方法讓子類實(shí)現(xiàn)动羽,修改adapter為抽象類,這將影響:
- getItemtype 使用抽象方法getDefItemViewType(int realDataPos)
- oncreateViewholder 返回的View需要根據(jù)自定義itemtype實(shí)現(xiàn)自定義view渔期,所以暴露抽象方法onCreateDefViewHolder(ViewGroup parent, int viewType)
- onBindViewHolder 綁定數(shù)據(jù)時(shí)需要根據(jù)自定義的ViewHolder來自定視圖數(shù)據(jù)的綁定运吓,所以暴露抽象方法onBindDefViewHolder(VH holder, int realDataPos)
這樣我們便能夠自定義itemType
getItemtype 使用抽象方法getDefItemViewType(int realDataPos)
public int getItemViewType(int position) {
int datasize = (datas == null ? 0 : datas.size());
int headerCount = hasHeader ? 1 : 0;
if(position < headerCount)
return ITEM_TYPE_HEADER;
int realIndex = position - headerCount;
if(realIndex < datasize){
return getDefItemViewType(realIndex);
}
else{
return ITEM_TYPE_FOOTER;
}
}
//multi item must be override
protected int getDefItemViewType(int realDataPos) {
//datas position item Type
return ITEM_TYPE_NORMAL;
}
暴露抽象方法onCreateDefViewHolder(ViewGroup parent, int viewType)
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
View view = null;
switch (viewType)
{
case ITEM_TYPE_HEADER:
view = LayoutInflater.from(parent.getContext()).inflate(headerLayout, parent, false);
break;
case ITEM_TYPE_FOOTER:
view = LayoutInflater.from(parent.getContext()).inflate(footerLayout, parent, false);
break;
default:
view = onCreateDefViewHolder(parent,viewType);
}
//實(shí)例化VH對(duì)象
return createViewHolder(view);
}
//be override
abstract View onCreateDefViewHolder(ViewGroup parent, int viewType);
回顧的時(shí)候發(fā)現(xiàn)還是返回VH類型的Viewholder容易定制渴邦,這樣自定義實(shí)現(xiàn)就不需要泛型實(shí)例化方法
abstract VH onCreateDefViewHolder(ViewGroup parent, int viewType);
暴露抽象方法onBindDefViewHolder(VH holder, int realDataPos)
public void onBindViewHolder(VH holder, int position) {
autoLoadMore(position);
if(position < (hasHeader ? 1 : 0))
{
// this is header view
return ;
}
int realDataPos = adjustPositionByType(position);
if(realDataPos < datas.size())
{
onBindDefViewHolder(holder,realDataPos);
}
else{
//this is footer View
}
}
//be override
abstract void onBindDefViewHolder(VH holder, int realDataPos);
我們的ItemType是由傳入的數(shù)據(jù)類型決定的,可以定義一個(gè)接口拘哨,讓傳入的數(shù)據(jù)類型實(shí)現(xiàn)該接口并且實(shí)現(xiàn)getItemType
public interface ItemType {
int getItemType();
}
public class MultiAdapter<T extends ItemType,VH extends MyViewHolder> extends BackQuickAdapter<T,VH>{
public MultiAdapter(List<T> datas) {
super(datas);
}
@Override
View onCreateDefViewHolder(ViewGroup parent, int viewType) {
return LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list, parent, false);
}
@Override
void onBindDefViewHolder(VH holder, int realDataPos) {
View contentView = holder.itemView;
String args = "自定義數(shù)據(jù)類型:"+String.valueOf(datas.get(realDataPos).getItemType());
((TextView)contentView.findViewById(R.id.recycler_list_txt)).setText(args);
}
@Override
protected int getDefItemViewType(int realDataPos) {
return datas.get(realDataPos).getItemType();
}
}
這樣就可以在外部自定義數(shù)據(jù)類型了
添加分組
首先我們看BRAVH怎么介紹
- 實(shí)體數(shù)據(jù)集類型要繼承SectionEntity
Stop,我們到這邊似乎不必要去看他怎么實(shí)現(xiàn)了谋梭,我猜原理應(yīng)該和上面添加自定義類型是一樣的,上面更加廣泛倦青,所以這里我們只有2種類型而已瓮床,一種分組頭類型。一種分組內(nèi)容類型姨夹。
我們開始編寫代碼試試:
- 寫一個(gè)數(shù)據(jù)集類型實(shí)現(xiàn)ItemType接口
- 數(shù)據(jù)集返回2種類型纤垂,第一種是分組頭類型假定(GroupHeader),第二種是一種分組內(nèi)容類型(GroupContent)
- 編寫我們的Adapter傳入?yún)?shù)類型為1的類型
我們先寫一個(gè)數(shù)據(jù)集類型實(shí)現(xiàn)ItemType接口
public class GroupEntity implements ItemType{
public final static int GROUPHEADER = 0X11;
public final static int GROUPCONTENT = 0X12;
private boolean isHeader = false;
private String values;
public GroupEntity(boolean isHeader, String values) {
this.isHeader = isHeader;
this.values = values;
}
@Override
public int getItemType() {
return isHeader ? GROUPHEADER : GROUPCONTENT;
}
}
這樣添加分組就是2種自定義數(shù)據(jù)類型而已,我們可以寫一個(gè)實(shí)體類磷账,返回2種類型峭沦,使用MultiAdapter適配,實(shí)現(xiàn)方法:
- onCreateDefViewHolder:根據(jù)viewType來inflate不同的layout的子view
- onBindDefViewHolder:根據(jù)Viewholder的VH holder, int position來綁定itemview與數(shù)據(jù)
分組的伸縮欄
既然要實(shí)現(xiàn)分組逃糟,我的思路是這樣的
- 是否需要提供不同的itemtype吼鱼,然后根據(jù)不同itemtype提供不同級(jí)別的子View,這樣視圖倒是沒有問題了绰咽。
- 下面需要思考的是數(shù)據(jù)菇肃,如果想要添加到列表的數(shù)據(jù)集中,之前我們定義的是T類型取募,那么不同級(jí)別也是要是T類型的才能加入到列表的數(shù)據(jù)集中
- 然后插入notifyitemInserted琐谤,刪除notifyitemremoved這樣就沒問題了.
可是設(shè)計(jì)主實(shí)體類或許有些麻煩了,要求里面有個(gè)子數(shù)據(jù)集類型是實(shí)體類類型的:
我們先定義接口
public interface Expandable<E> extends ItemType{
List<E> subItems();
boolean isExpandable();
void setExpand(boolean expand);
boolean isExpand();
}
這個(gè)接口要求子數(shù)據(jù)級(jí)玩敏,是否可以擴(kuò)展
然后定義數(shù)據(jù)類型
public class ExpandEntity implements Expandable<ExpandEntity>{
public final static int SUB1 = 0x111;
public final static int SUB2 = 0x112;
// public final static int SUB3 = 0x113;
private int itemType;
private List<ExpandEntity> subDatas;
private String values;
public ExpandEntity(int itemType, List<ExpandEntity> subDatas,String values) {
this.itemType = itemType;
this.subDatas = subDatas;
this.values = values;
}
public String getValues() {
return values;
}
@Override
public int getItemType() {
return itemType;
}
@Override
public List<ExpandEntity> subItems() {
return subDatas;
}
@Override
public boolean isExpandable() {
return subDatas != null && subDatas.size() > 0;
}
boolean isExpand = false;
@Override
public void setExpand(boolean expand) {
isExpand = expand;
}
@Override
public boolean isExpand() {
return isExpand;
}
}
這樣就可以實(shí)現(xiàn)該接口斗忌,外部類自由繼承,然后自由添加values屬性
下面我們的接口實(shí)體類好了旺聚,需要制作adapter织阳,可是adapter怎么寫呢?我們需要傳入的數(shù)據(jù)類型為Expandable類型砰粹,而且數(shù)據(jù)集合類型要是Expandable的實(shí)現(xiàn)類唧躲,是否可以這樣寫?
class ExpandAdapter<I extends Expandable<I>,VH extends MyViewHolder> extends BackQuickAdapter<I,VH>
這樣保證數(shù)據(jù)集市I類型碱璃,I又是Expandable類型弄痹,這樣可以遍歷I的子數(shù)據(jù)集實(shí)現(xiàn)多級(jí)的展開與隱藏
Adapter具體實(shí)現(xiàn)該怎樣呢?
我們可以在onBindDefViewHolder方法里面添加itemview的點(diǎn)擊事件厘贼,然后為itemview添加tag界酒,tag里面是綁定的數(shù)據(jù),再實(shí)現(xiàn)點(diǎn)擊事件的時(shí)候取出tag里面數(shù)據(jù)嘴秸,判斷單項(xiàng)是否可以展開,如果可以展開,得到子數(shù)據(jù)集放入主數(shù)據(jù)集中岳掐,然后notifyItemRangeInserted就能實(shí)現(xiàn)數(shù)據(jù)的多級(jí)展開
void onBindDefViewHolder(VH holder, int realDataPos) {
ExpandEntity entity = (ExpandEntity) datas.get(realDataPos);
((TextView)holder.itemView.findViewById(R.id.recycler_list_txt)).setText(entity.getValues());
holder.itemView.setTag(datas.get(realDataPos));
holder.itemView.setOnClickListener(new ClickDelegate(realDataPos));
}
private class ClickDelegate implements View.OnClickListener{
//當(dāng)前位置之后插入+headercount
private int position = 0;
public ClickDelegate(int position) {
this.position = position;
}
@Override
public void onClick(View v) {
Expandable<I> raw = (Expandable<I>) v.getTag();
if(raw.isExpandable() && !raw.isExpand()){
//toggle this subItem
//expand or compose
datas.addAll(position+1,raw.subItems());
//from start +2 to datas.size count number
notifyItemRangeInserted(position + 1 + 1, raw.subItems().size());
raw.setExpand(true);
Log.i("itemclick","expand");
}else if(raw.isExpand()){
//這里需要折疊凭疮,去除datas中間的數(shù)據(jù),多級(jí)遍歷刪除所有當(dāng)前項(xiàng)的子項(xiàng)
Log.i("itemclick","compose");
}
}
}
注意這里移除操作串述,去除datas中間的數(shù)據(jù)执解,實(shí)現(xiàn)折疊效果,然后notifyItemRangeMoved
這部分的邏輯也是對(duì)主數(shù)據(jù)集datas操作纲酗,這里沒有具體實(shí)現(xiàn)衰腌,有心的小伙伴可以看BRAVH的expand與collapse方法,人家的折疊可是多級(jí)折疊的觅赊,將所有子集都移除然后notifyItemRangeMoved右蕊。這里我就不寫這部分邏輯代碼了。
我是分割線
這里我們寫Adapter需要涉及到一個(gè)泛型的實(shí)例化吮螺,因?yàn)樾枰獙iew加入Viewholder饶囚,并把Viewholder實(shí)例化,而Viewholder又是VH類型的鸠补,所以下面方法我直接貼上代碼
/**
* 抽象類反射實(shí)例化
* @param view
* @return
*/
protected VH createViewHolder(View view) {
Class temp = getClass();
Class z = null;
while (z == null && null != temp) {
z = getInstancedGenericKClass(temp);
temp = temp.getSuperclass();
}
VH k;
// 泛型擦除會(huì)導(dǎo)致z為null
if (z == null) {
k = (VH) new MyViewHolder(view);
} else {
k = createGenericKInstance(z, view);
}
return k != null ? k : (VH) new MyViewHolder(view);
}
/**
* try to create Generic K instance
*
* @param z
* @param view
* @return
*/
@SuppressWarnings("unchecked")
private VH createGenericKInstance(Class z, View view) {
try {
Constructor constructor;
// inner and unstatic class
if (z.isMemberClass() && !Modifier.isStatic(z.getModifiers())) {
constructor = z.getDeclaredConstructor(getClass(), View.class);
constructor.setAccessible(true);
return (VH) constructor.newInstance(this, view);
} else {
constructor = z.getDeclaredConstructor(View.class);
constructor.setAccessible(true);
return (VH) constructor.newInstance(view);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
/**
* get generic parameter K
*
* @param z
* @return
*/
private static Class getInstancedGenericKClass(Class z) {
Type type = z.getGenericSuperclass();
if (type instanceof ParameterizedType) {
Type[] types = ((ParameterizedType) type).getActualTypeArguments();
for (Type temp : types) {
if (temp instanceof Class) {
Class tempClass = (Class) temp;
if (MyViewHolder.class.isAssignableFrom(tempClass)) {
return tempClass;
}
}
}
}
return null;
}
這樣泛型的實(shí)例化就完成了~
又到總結(jié)時(shí)間啦萝风。我們模擬BRAVH能夠?qū)W到什么?
我們?cè)趯慉dapter的時(shí)候。將數(shù)據(jù)集類型以泛型的形式傳入紫岩。
在Adapter中抽象出onBindViewHolder,onCreateViewHolder规惰,除了處理預(yù)置的類型,比如頭布局泉蝌,尾布局歇万,空布局,loading布局梨与。其他的都需要自定義ItemType數(shù)據(jù)類型來實(shí)現(xiàn)定制view堕花。
擴(kuò)展與折疊也是屬于自定義數(shù)據(jù)類型中的一種,但是要求傳入的數(shù)據(jù)集類型T中還有T類型的子集合粥鞋,用來得到子集缘挽,這樣可以保持與Adapter
的數(shù)據(jù)類型一直,用于展開刪除其實(shí)就是對(duì)Adapter中的數(shù)據(jù)集datas插入與刪除然后通知刷新而已
拖拽與滑動(dòng)刪除默認(rèn)ItemTouhHelper,在onmoved與onswipe中交換數(shù)據(jù)集中的位置或者刪除某個(gè)位置來通知刷新