|
为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;}}1 | | |