配色: 字号:
为RecyclerView打造通用Adapter
2016-11-10 | 阅:  转:  |  分享 
  
为RecyclerView打造通用Adapter

##RecycleView简介

RecyclerView控件和ListView的原理有很多相似的地方,都是维护少量的View来进行显示大量的数据,不过RecyclerView控件比ListView更加高级并且更加灵活。当我们的数据因为用户事件或者网络事件发生改变的时候也能很好的进行显示。和ListView不同的是,RecyclerView不用在负责Item显示相关的功能,所有有关布局、绘制、数据绑定等都被分拆成不同的类进行管理。同时RecyclerView控件提供了以下两种方法来进行简化和处理大数量集合:

1.基本使用

RecycleView的基本使用

RecycleView导包(可有可无)dependencies中添加

compile''com.android.support:recyclerview-v7:23.1.1''

在布局文件中定义




android:id="@+id/rcv_history"

android:layout_width="match_parent"

android:layout_height="match_parent">



3.对其进行初始化



rcv_history=(RecyclerView)findViewById(R.id.rcv_history);

4.LinearLayoutManager和GrideLayouManager两种显示风格



//LinearLayoutManager(ListView)

rcv_history.setLayoutManager(new(HistoryActivity.this));



//GridLayoutManager(GrideView)



//第二个参数就是GridView一样一行显示个个数

rcv_history.setLayoutManager(newGridLayoutManager(HistoryActivity.this,2));



rcv_history.setAdapter(Adapter);



创建一个类继承RecycleView.Adapter

5.RecycleView.Adapter==>classHistoryAdapterextendsRecyclerView.Adapter//指定泛型



创建一个类集成RecycleView.ViewHolder()



//返回的是一个Holder

@Override

//i不是下标而是类型如何实现了getItemViewType()//

//onCreateViewHolder加载对应布局,初始化对应的holder,每种布局对应自己的holder

publicHistoryAdapter.MediaHolderonCreateViewHolder(ViewGroupviewGroup,intviewType){

MediaHolderholder=newMediaHolder(LayoutInflater.from(HistoryActivity.this).inflate(R.layout.item_history,null));

Viewview=null;

ViewHolderholder=null;

switch(viewType){case...break}//根据类型的不同加载对应的布局



returnholder;

}





classMediaHolderextendsRecycleView.ViewHolder{

Viewview;



publicMediaHolder(ViewitemView){//构造器itemView列表中的item,类似convertView

super(itemView);

this.view=itemView;//对item布局进行初始化

//textView=itemView.findViewById(R.id.textView);

iv_item_history_icon=(ImageView)itemView.findViewById(R.id.iv_item_history_icon);

tv_item_history_title=(TextView)itemView.findViewById(R.id.tv_item_history_title);

tv_item_history_duration=(TextView)itemView.findViewById(R.id.tv_item_history_duration);

iv_item_history_del=(ImageView)itemView.findViewById(R.id.iv_item_history_del);

}

}



6.//onBindViewHolder绑定对应的holder,加载对应的布局

设置Item的显示//第一个参数onCreateViewHolder中返回的Holder类型第二个参数指定的下标

publicvoidonBindViewHolder(HistoryAdapter.MediaHolderholder,finalintposition){holder.ivitemhistory_icon.setImageResource();}//返回Item的总大小

@OverridepublicintgetItemCount(){if(mediaInfos!=null){returnmediaInfos.size();

}else{

return0;

}

}

7.自定义RecycleView的监听1.自定义RecycleView2.Adapter里设置监听



1.创建一个接口

publicinterfaceRecycleItemClickListener{

voidonItemClickListener(Viewview,intposition);

}



2.声明变量

RecycleItemClickListenerlistener;

3.set方法

publicvoidsetRecycleItemClickListener(RecycleItemClickListenerrecycleItemClickListener){

this.recycleItemClickListener=recycleItemClickListener;

}

4.实现的地方

//在Hodler中得到itemVidew对象

//this.view=itemView;在ViewHolder个构造器里获得其View

在onBindViewHolder下//在此才有position

publicvoidonBindViewHolder(HistoryAdapter.MediaHolderholder,finalintposition){

holder.view.setOnClickListener(newOnClickListener(){

publicvoidonClick(Viewv){

if(listener!=null){

listener.onItemClickListener(holder.view,position)

}

}

});

}



5.实现监听

adapter.setRecycleItemClickListener(newRecycleItemClickListener(

publicvoidonItemClickListener(holder.view,position){

//对其进行一系列的操作

}

))



----------------------------------------------------------------------------------------------------------------------------------------------



详细使用



采用LayoutManager来处理Item的布局



提供Item操作的默认动画,例如在增加或者删除item的时候



为了使用RecyclerView控件,我们需要创建一个Adapter和一个LayoutManager:



Adapter:继承自RecyclerView.Adapetr类,主要用来将数据和布局item进行绑定。



LayoutManager:布局管理器,设置每一项view在RecyclerView中的位置布局以及控件itemview的显



示或者隐藏。当View重用或者回收的时候,LayoutManger都会向Adapter来请求新的数据来进行替换原来数据的内容。这种回收重用的机制可以提供性能,避免创建很多的view或者是频繁的调用findViewById方法。这种机制和ListView还是很相似的。



RecyclerView提供了三种内置的LayoutManager:



LinearLayoutManager:线性布局,横向或者纵向滑动列表





GridLayoutManager:表格布局





StaggeredGridLayoutManager:流式布局,例如瀑布流效果





优点:插拔式,高度的解耦,异常灵活



#主要API

LayoutManager:布局管理器(LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager)



ItemDecoration:绘制Item间的间隔



ItemAnimator:Item增删的动画



#使用步骤

1.build.gradle中添加



dependencies{

……



compile''com.android.support:recyclerview-v7:23.1.1''

}



2.布局内添加




android:id="@+id/recyclerView"

android:layout_width="match_parent"

android:layout_height="match_parent"

>



3.代码中初始化并设置



RecyclerViewrecycleView=findView(R.id.recyclerview);



设置布局管理器



LinearLayoutManagerlinearLayoutManager=newLinearLayoutManager(this);//线性



GridLayoutManagergridLayoutManager=newGridLayoutManager(this,4);//网格



StaggeredGridLayoutManagerstaggeredGridLayoutManager=newStaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL);//流式



设置布局管理器的方向



linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);

linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);



设置



recyclerView.setLayoutManager(layout);

recyclerView.setAdapter(adapter);

recyclerView.addItemDecoration(newDividerGridItemDecoration(this));//添加分割线,继承RecyclerView.ItemDecoration

recyclerView.setItemAnimator(newDefaultItemAnimator());//设置默认Item增删动画



#Adapter的实现



1.自定义类继承RecycleView的Adapter同时绑定ViewHolder



classMyAdapterextendsRecyclerView.Adapter





2.实现方法



@Override

publicMyViewHolderonCreateViewHolder(ViewGroupparent,intviewType){

LayoutInflatermInflater=LayoutInflater.from(context);

MyViewHolderholder=newMyViewHolder(mInflater.inflate(

R.layout.item_home,parent,false));

returnholder;

}



@Override

publicvoidonBindViewHolder(MyViewHolderholder,intposition){

holder.tv.setText(mDatas.get(position));

}



@Override

publicintgetItemCount(){

returnmDatas.size();

}

3.MyViewHolder



classMyViewHolderextendsRecyclerView.ViewHolder{



TextViewtv;



publicMyViewHolder(Viewview){

super(view);

tv=(TextView)view.findViewById(R.id.id_num);

}

}



#增删Item的动画

mDatas.add(position,"InsertOne");

notifyItemInserted(position);//增加

mDatas.remove(position);

notifyItemRemoved(position);//删除



#设置点击监听



1.在Adapter中自定义监听



publicinterfaceOnItemClickLitener{

voidonItemClick(Viewview,intposition);



voidonItemLongClick(Viewview,intposition);

}



privateOnItemClickLitenermOnItemClickLitener;



publicvoidsetOnItemClickLitener(OnItemClickLitenermOnItemClickLitener){

this.mOnItemClickLitener=mOnItemClickLitener;

}



2.在onBindViewHolder方法中绑定



if(mOnItemClickLitener!=null){

holder.itemView.setOnClickListener(newOnClickListener(){

@Override

publicvoidonClick(Viewv){

intpos=holder.getLayoutPosition();

mOnItemClickLitener.onItemClick(holder.itemView,pos);

}

});



holder.itemView.setOnLongClickListener(newOnLongClickListener(){

@Override

publicbooleanonLongClick(Viewv){

intpos=holder.getLayoutPosition();

mOnItemClickLitener.onItemLongClick(holder.itemView,pos);

removeData(pos);

returnfalse;

}

});

}



3.在Activity中设置监听



mAdapter.setOnItemClickLitener(newHomeAdapter.OnItemClickLitener(){

@Override

publicvoidonItemClick(Viewview,intposition){

Toast.makeText(HomeActivity.this,position+"click",

Toast.LENGTH_SHORT).show();

}



@Override

publicvoidonItemLongClick(Viewview,intposition){

Toast.makeText(HomeActivity.this,position+"longclick",

Toast.LENGTH_SHORT).show();

}

});

#分类型的RecycleView

1.MyAdapter继承RecyclerView.Adapter



classMyAdapterextendsRecyclerView.Adapter



2.通过枚举定义不同的Item



//枚举Item

publicenumITEM_TYPE{

ITEM1,

ITEM2,

ITEM3,

ITEM4

}



3.根据不同的Item加载不同的ViewHolder



@Override

publicRecyclerView.ViewHolderonCreateViewHolder(ViewGroupparent,intviewType){

//加载的时候,根据不同的Item加载不同的布局

//Enum类提供了一个ordinal()方法,返回枚举类型的序数,这里ITEM_TYPE.ITEM1.ordinal()代表0,ITEM_TYPE.ITEM2.ordinal()代表1

if(viewType==ITEM_TYPE.ITEM1.ordinal()){

returnnewItem1ViewHolder(layoutInflater.inflate(R.layout.item1,parent,false));

}elseif(viewType==ITEM_TYPE.ITEM2.ordinal()){

returnnewItem2ViewHolder(layoutInflater.inflate(R.layout.item2,parent,false));

}elseif(viewType==ITEM_TYPE.ITEM3.ordinal()){

returnnewItem3ViewHolder(layoutInflater.inflate(R.layout.item3,parent,false));

}else{

returnnewItem4ViewHolder(layoutInflater.inflate(R.layout.item4,parent,false));

}

}



4.根据position返回不同类型的Item



@Override

publicintgetItemViewType(intposition){



if(position
returnITEM_TYPE.ITEM1.ordinal();

}elseif(position
returnITEM_TYPE.ITEM2.ordinal();

}elseif(position
returnITEM_TYPE.ITEM3.ordinal();

}elseif(position
returnITEM_TYPE.ITEM4.ordinal();

}

returnsuper.getItemViewType(position);

}



5.根据Item的类型设置数据



@Override

publicvoidonBindViewHolder(RecyclerView.ViewHolderholder,intposition){

//根据holder的类型设置数据

if(holderinstanceofItem1ViewHolder){



if(position
((Item1ViewHolder)holder).tv1.setText(item1.get(position));

}



}elseif(holderinstanceofItem1ViewHolder){



if(position>item1.size()&&position
((Item2ViewHolder)holder).tv2.setText(item2.get(position));

}



}else{

......

}

}

6.返回总数量



@Override

publicintgetItemCount(){

returnitem1.size()+item2.size()+item3.size()+item4.size();

}



7.创建ViewHolder



publicstaticclassItem1ViewHolderextendsRecyclerView.ViewHolder{



TextViewtv;



publicItem1ViewHolder(ViewitemView){

super(itemView);

tv=(TextView)itemView.findViewById(R.id.tv);

}

}



publicstaticclassItem2ViewHolderextendsRecyclerView.ViewHolder{



TextViewtv;



publicItem2ViewHolder(ViewitemView){

super(itemView);

tv=(TextView)itemView.findViewById(R.id.tv);

}

}



publicstaticclassItem3ViewHolderextendsRecyclerView.ViewHolder{



TextViewtv;



publicItem3ViewHolder(ViewitemView){

super(itemView);

tv=(TextView)itemView.findViewById(R.id.tv);

}

}



publicstaticclassItem4ViewHolderextendsRecyclerView.ViewHolder{



TextViewtv;



publicItem4ViewHolder(ViewitemView){

super(itemView);

tv=(TextView)itemView.findViewById(R.id.tv);

}

}



......



------------------------------------------------------------------------------------------------------------------------------------------------



通用adapter

参考自:http://blog.csdn.net/lmj623565791/article/details/47251585;本文出自:【张鸿洋的博客】

一、概述



记得好久以前针对ListView类控件写过一篇打造万能的ListViewGridView适配器,如今RecyclerView异军突起,其Adapter的用法也与ListView类似,那么我们也可以一步一步的为其打造通用的Adapter,使下列用法书写更加简单:



简单的数据绑定(单种Item)

多种ItemType数据绑定

增加onItemClickListener,onItenLongClickListener

优雅的添加分类header

二、使用方式和效果图



在一步一步完成前,我们先看下使用方式和效果图:



(1)简单的数据绑定



首先看我们最常用的单种Item的书写方式:



mRecyclerView.setAdapter(newCommonAdapter(this,R.layout.item_list,mDatas){@Overridepublicvoidconvert(ViewHolderholder,Strings){holder.setText(R.id.id_item_list_title,s);}});1234567812345678

是不是相当方便,在convert方法中完成数据、事件绑定即可。



(2)多种ItemViewType



多种ItemViewType,正常考虑下,我们需要根据Item指定ItemType,并且根据ItemType指定相应的布局文件。我们通过MultiItemTypeSupport完成指定:



MultiItemTypeSupportmultiItemSupport=newMultiItemTypeSupport(){@OverridepublicintgetLayoutId(intitemType){//根据itemType返回item布局文件id}@OverridepublicintgetItemViewType(intpostion,ChatMessagemsg){//根据当前的bean返回itemtype}}123456789101112131415123456789101112131415

剩下就简单了,将其作为参数传入到MultiItemCommonAdapter即可。



mRecyclerView.setAdapter(newSectionAdapter(this,mDatas,multiItemSupport){@Overridepublicvoidconvert(ViewHolderholder,Strings){holder.setText(R.id.id_item_list_title,s);}});1234567812345678

贴个效果图:







(3)添加分类header



其实属于多种ItemViewType的一种了,只是比较常用,我们就简单封装下。



依赖正常考虑下,这种方式需要额外指定header的布局,以及布局中显示标题的TextView了,以及根据Item显示什么样的标题。我们通过SectionSupport对象指定:



SectionSupportsectionSupport=newSectionSupport(){@OverridepublicintsectionHeaderLayoutId(){returnR.layout.header;}@OverridepublicintsectionTitleTextViewId(){returnR.id.id_header_title;}@OverridepublicStringgetTitle(Strings){returns.substring(0,1);}};12345678910111213141516171819201234567891011121314151617181920

3个方法,一个指定header的布局文件,一个指定布局文件中显示title的TextView,最后一个用于指定显示什么样的标题(根据Adapter的Bean)。



接下来就很简单了:



mRecyclerView.setAdapter(newSectionAdapter(this,R.layout.item_list,mDatas,sectionSupport){@Overridepublicvoidconvert(ViewHolderholder,Strings){holder.setText(R.id.id_item_list_title,s);}});1234567812345678

这样就完了,效果图如下:







ok,看完上面简单的介绍,相信你已经基本了解了,没错,和我上篇ListView万能Adapter的使用方式基本一样,并且已经封装到同一个库了,链接为:https://github.com/hongyangAndroid/base-adapter,此外还提供了ItemClick,ItemLongClick,添加EmptyView等支持。



说了这么多,下面进入正题,看我们如何一步步完成整个封装的过程。



三、通用的ViewHolder



RecyclerView要求必须使用ViewHolder模式,一般我们在使用过程中,都需要去建立一个新的ViewHolder然后作为泛型传入Adapter。那么想要建立通用的Adapter,必须有个通用的ViewHolder。



首先我们确定下ViewHolder的主要的作用,实际上是通过成员变量存储对应的convertView中需要操作的字View,避免每次findViewById,从而提升运行的效率。



那么既然是通用的View,那么对于不同的ItemType肯定没有办法确定创建哪些成员变量View,取而代之的只能是个集合来存储了。



那么代码如下:



publicclassViewHolderextendsRecyclerView.ViewHolder{privateSparseArraymViews;privateViewmConvertView;privateContextmContext;publicViewHolder(Contextcontext,ViewitemView,ViewGroupparent){super(itemView);mContext=context;mConvertView=itemView;mViews=newSparseArray();}publicstaticViewHolderget(Contextcontext,ViewGroupparent,intlayoutId){ViewitemView=LayoutInflater.from(context).inflate(layoutId,parent,false);ViewHolderholder=newViewHolder(context,itemView,parent,position);returnholder;}/通过viewId获取控件@paramviewId@return/publicTgetView(intviewId){Viewview=mViews.get(viewId);if(view==null){view=mConvertView.findViewById(viewId);mViews.put(viewId,view);}return(T)view;}}123456789101112131415161718192021222324252627282930313233343536373839404142123456789101112131415161718192021222324252627282930313233343536373839404142

代码很简单,我们的ViewHolder继承自RecyclerView.ViewHolder,内部通过SparseArray来缓存我们itemView内部的子View,从而得到一个通用的ViewHolder。每次需要创建ViewHolder只需要传入我们的layoutId即可。



ok,有了通用的ViewHolder之后,我们的通用的Adapter分分钟就出来了。



四、通用的Adapter



我们的每次使用过程中,针对的数据类型Bean肯定是不同的,那么这里肯定要引入泛型代表我们的Bean,内部通过一个List代表我们的数据,ok,剩下的看代码:



packagecom.zhy.base.adapter.recyclerview;importandroid.content.Context;importandroid.support.v7.widget.RecyclerView;importandroid.view.LayoutInflater;importandroid.view.View;importandroid.view.ViewGroup;importcom.zhy.base.adapter.ViewHolder;importjava.util.List;/Createdbyzhyon16/4/9./publicabstractclassCommonAdapterextendsRecyclerView.Adapter{protectedContextmContext;protectedintmLayoutId;protectedListmDatas;protectedLayoutInflatermInflater;publicCommonAdapter(Contextcontext,intlayoutId,Listdatas){mContext=context;mInflater=LayoutInflater.from(context);mLayoutId=layoutId;mDatas=datas;}@OverridepublicViewHolderonCreateViewHolder(finalViewGroupparent,intviewType){ViewHolderviewHolder=ViewHolder.get(mContext,parent,mLayoutId);returnviewHolder;}@OverridepublicvoidonBindViewHolder(ViewHolderholder,intposition){holder.updatePosition(position);convert(holder,mDatas.get(position));}publicabstractvoidconvert(ViewHolderholder,Tt);@OverridepublicintgetItemCount(){returnmDatas.size();}}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354

继承自RecyclerView.Adapter,需要复写的方法还是比较少的。首先我们使用过程中传输我们的数据集mDatas,和我们item的布局文件layoutId。



onCreateViewHolder时,通过layoutId即可利用我们的通用的ViewHolder生成实例。



onBindViewHolder这里主要用于数据、事件绑定,我们这里直接抽象出去,让用户去操作。可以看到我们修改了下参数,用户可以拿到当前Item所需要的对象和viewHolder去操作。



那么现在用户的使用是这样的:



mRecyclerView.setAdapter(newCommonAdapter(this,R.layout.item_list,mDatas){@Overridepublicvoidconvert(ViewHolderholder,Strings){TextViewtv=holder.getView(R.id.id_item_list_title);tv.setText(s);}});123456789123456789

看到这里,爽了很多,目前我们仅仅写了很少的代码,但是我们的通用的Adapter感觉已经初步完成了。



可以看到我们这里通过viewholder根据控件的id拿到控件,然后再进行数据绑定和事件操作,我们还能做些什么简化呢?



恩,我们可以通过一些辅助方法简化我们的代码,所以继续往下看。



五、进一步封装ViewHolder



我们的Item实际上使用的控件较多时候可能都是TextView,ImageView等,我们一般在convert方法都是去设置文本,图片什么的,那么我们可以在ViewHolder里面,写上如下的一些辅助方法:



classViewHolderextendsRecyclerView.Adapter<ViewHolder>{//...publicViewHoldersetText(intviewId,Stringtext){TextViewtv=getView(viewId);tv.setText(text);returnthis;}publicViewHoldersetImageResource(intviewId,intresId){ImageViewview=getView(viewId);view.setImageResource(resId);returnthis;}publicViewHoldersetOnClickListener(intviewId,View.OnClickListenerlistener){Viewview=getView(viewId);view.setOnClickListener(listener);returnthis;}}12345678910111213141516171819202122232425261234567891011121314151617181920212223242526

当然上面只给出了几个方法,你可以把常用控件的方法都写进去,并且在使用过程中不断完善即可。



有了一堆辅助方法后,我们的操作更加简化了一步。



mRecyclerView.setAdapter(newCommonAdapter(this,R.layout.item_list,mDatas){@Overridepublicvoidconvert(ViewHolderholder,Strings){//TextViewtv=holder.getView(R.id.id_item_list_title);//tv.setText(s);holder.setText(R.id.id_item_list_title,s);}});1234567891012345678910

ok,到这里,我们的针对单种ViewItemType的通用Adapter就完成了,代码很简单也很少,但是简化效果非常明显。



ok,接下来我们考虑多种ItemViewType的情况。



六、多种ItemViewType



多种ItemViewType,一般我们的写法是:



复写getItemViewType,根据我们的bean去返回不同的类型

onCreateViewHolder中根据itemView去生成不同的ViewHolder

如果大家还记得,我们的ViewHolder是通用的,唯一依赖的就是个layoutId。那么上述第二条就变成,根据不同的itemView告诉我用哪个layoutId即可,生成viewholder这种事我们通用adapter来做。



于是,引入一个接口:



publicinterfaceMultiItemTypeSupport{intgetLayoutId(intitemType);intgetItemViewType(intposition,Tt);}123456123456

可以很清楚的看到,这个接口实际就是完成我们上述的两条工作。用户在使用过程中,通过实现上面两个方法,指明不同的Bean返回什么itemViewType,不同的itemView所对应的layoutId.



ok,有了上面这个接口,我们的参数就够了,下面开始我们的MultiItemCommonAdapter的编写。



publicabstractclassMultiItemCommonAdapter<T>extendsCommonAdapter<T>{protectedMultiItemTypeSupportmMultiItemTypeSupport;publicMultiItemCommonAdapter(Contextcontext,Listdatas,MultiItemTypeSupportmultiItemTypeSupport){super(context,-1,datas);mMultiItemTypeSupport=multiItemTypeSupport;}@OverridepublicintgetItemViewType(intposition){returnmMultiItemTypeSupport.getItemViewType(position,mDatas.get(position));}@OverridepublicViewHolderonCreateViewHolder(ViewGroupparent,intviewType){intlayoutId=mMultiItemTypeSupport.getLayoutId(viewType);ViewHolderholder=ViewHolder.get(mContext,parent,layoutId;returnholder;}}12345678910111213141516171819202122232425261234567891011121314151617181920212223242526

几乎没有几行代码,感觉简直不需要消耗脑细胞。getItemViewType用户的传入的MultiItemTypeSupport.getItemViewType完成,onCreateViewHolder中根据MultiItemTypeSupport.getLayoutId返回的layoutId,去生成ViewHolder即可。



ok,这样的话,我们的多种ItemViewType的支持也就完成了,一路下来感觉还是蛮轻松的~~~



最后,我们还有个添加分类的header,为什么想起来封装这个呢,这个是因为我看到了这么个项目:https://github.com/ragunathjawahar/simple-section-adapter,这个项目给了种类似装饰者模式的方法,为ListView添加了header,有兴趣可以看下。我想我们的RecylerView也来个吧,不过我们这里直接通过继承Adapter完成。



七、添加分类Header



话说添加分类header,其实就是我们多种ItemViewType的一种,那么我们需要知道哪些参数呢?



简单思考下,我们需要:



header所对应的布局文件

显示header的title对应的TextView

显示的title是什么(一般肯定根据Bean生成)

ok,这样的话,我们依然引入一个接口,用于提供上述3各参数



publicinterfaceSectionSupport{publicintsectionHeaderLayoutId();publicintsectionTitleTextViewId();publicStringgetTitle(Tt);}1234567812345678

方法名应该很明确了,这里引入泛型,对应我们使用时的数据类型Bean。



刚才也说了我们的分类header是多种ItemViewType的一种,那么直接继承MultiItemCommonAdapter实现。



publicabstractclassSectionAdapterextendsMultiItemCommonAdapter{privateSectionSupportmSectionSupport;privatestaticfinalintTYPE_SECTION=0;privateLinkedHashMapmSections;privateMultiItemTypeSupportheaderItemTypeSupport=newMultiItemTypeSupport(){@OverridepublicintgetLayoutId(intitemType){if(itemType==TYPE_SECTION)returnmSectionSupport.sectionHeaderLayoutId();elsereturnmLayoutId;}@OverridepublicintgetItemViewType(intposition,To){returnmSections.values().contains(position)?TYPE_SECTION:1;}};@OverridepublicintgetItemViewType(intposition){returnmMultiItemTypeSupport.getItemViewType(position,null);}finalRecyclerView.AdapterDataObserverobserver=newRecyclerView.AdapterDataObserver(){@OverridepublicvoidonChanged(){super.onChanged();findSections();}};publicSectionAdapter(Contextcontext,intlayoutId,Listdatas,SectionSupportsectionSupport){super(context,datas,null);mLayoutId=layoutId;mMultiItemTwww.baiyuewang.netypeSupport=headerItemTypeSupport;mSectionSupport=sectionSupport;mSections=newLinkedHashMap<>();findSections();registerAdapterDataObserver(observer);}@OverrideprotectedbooleanisEnabled(intviewType){if(viewType==TYPE_SECTION)returnfalse;returnsuper.isEnabled(viewType);}@OverridepublicvoidonDetachedFromRecyclerView(RecyclerViewrecyclerView){super.onDetachedFromRecyclerView(recyclerView);unregisterAdapterDataObserver(observer);}publicvoidfindSections(){intn=mDatas.size();intnSections=0;mSections.clear();for(inti=0;iget(i));if(!mSections.containsKey(sectionName)){mSections.put(sectionName,i+nSections);nSections++;}}}@OverridepublicintgetItemCount(){returnsuper.getItemCount()+mSections.size();}publicintgetIndexForPosition(intposition){intnSections=0;Set>entrySet=mSections.entrySet();for(Map.Entryentry:entrySet){if(entry.getValue()returnposition-nSections;}@OverridepublicvoidonBindViewHolder(ViewHolderholder,intposition){position=getIndexForPosition(position);if(holder.getItemViewType()==TYPE_SECTION){holder.setText(mSectionSupport.sectionTitleTextViewId(),mSectionSupport.getTitle(mDatas.get(position)));return;}super.onBindViewHolder(holder,position);}}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121

根据我们之前的代码,使用MultiItemCommonAdapter,需要提供一个MultiItemTypeSupport,我们这里当然也不例外。可以看到上述代码,我们初始化了成员变量headerItemTypeSupport,分别对getLayoutId和getItemViewType进行了实现。



getLayoutId如果type是header类型,则返回mSectionSupport.sectionHeaderLayoutId();否则则返回mLayout.

getItemViewType根据位置判断,如果当前是header所在位置,返回header类型常量;否则返回1.

ok,可以看到我们构造方法中调用了findSections(),主要为了存储我们的title和对应的position,通过一个MapmSections来存储。



那么对应的getItemCount()方法,我们多了几个title肯定总数会增加,所以需要复写。



在onBindViewHolder中我们有一行重置position的代码,因为我们的position变大了,所以在实际上绑定我们数据时,这个position需要还原,代码逻辑见getIndexForPosition(position)。



最后一点就是,每当我们的数据发生变化,我们的title集合,即mSections就可能会发生变化,所以需要重新生成,本来准备复写notifyDataSetChanged方法,在里面重新生成,没想到这个方法是final的,于是利用了registerAdapterDataObserver(observer);,在数据发生变化回调中重新生成,记得在onDetachedFromRecyclerView里面对注册的observer进行解注册。



ok,到此我们的增加Header就结束了~~



恩,上面是针对普通的Item增加header的代码,如果是针对多种ItemViewType呢?其实也很简单,这种方式需要传入MultiItemTypeSupport。那么对于headerItemTypeSupport中的getItemViewType等方法,不是header类型时,交给传入的MultiItemTypeSupport即可,大致的代码如下:



headerItemTypeSupport=newMultiItemTypeSupport(){@OverridepublicintgetLayoutId(intitemType){if(itemType==TYPE_SECTION)returnmSectionSupport.sectionHeaderLayoutId();elsereturnmultiItemTypeSupport.getLayoutId(itemType);}@OverridepublicintgetItemViewType(intposition,To){intpositionVal=getIndexForPosition(position);returnmSections.www.wang027.comvalues().contains(position)?TYPE_SECTION:multiItemTypeSupport.getItemViewType(positionVal,o);}};12345678910111213141516171819201234567891011121314151617181920

那么这样的话,今天的博客就结束了,有几点需要说明下:



本来是想接着以前的万能Adapter后面写,但是为了本文的独立和完整性,还是尽可能没有去依赖上篇博客的内容了。



此外,文章最后给出的开源代码与上述代码存在些许的差异,因为开源部分源码整合了ListView,RecyclerView等,而本文上述代码完全针对RecyclerView进行编写。

献花(0)
+1
(本文系thedust79首藏)