欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android开发之RecyclerView的使用

程序员文章站 2022-03-16 15:56:27
Android开发之RecyclerView的使用。自Android5.0之后,谷歌公司推出了RecylerView控件,RecylerView,我想看到一个新名词后大部分人会首先...

Android开发之RecyclerView的使用。自Android5.0之后,谷歌公司推出了RecylerView控件,RecylerView,我想看到一个新名词后大部分人会首先发出一个疑问,recylerview是什么为什么会有recylerview也就是说recylerview的优点是什么recylerview怎么用接下来就对这几个问题来一起讨论一下recylerview,如有谬误欢迎批评指正。

通过本文,你将学到以下知识点

①RecyclerView与ListView相比它的优点

②RecyclerView的初步用法

③RecyclerView增加分隔线

④RecyclerView更改分隔线的样式

⑤RecyclerView的Adapter的用法

⑥RecyclerView.Adapter中刷新的几个方法的对比

⑦给RecyclerView增加条目点击事件

1.RecyclerView是什么

RecylerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,同样拥有item回收复用的功能,这一点从它的名字recylerview即回收view也可以看出。看到这也许有人会问,不是已经有ListView了吗,为什么还要RecylerView呢这就牵扯到第二个问题了。

2.RecyclerView的优点是什么

根据官方的介绍RecylerView是ListView的升级版,既然如此那RecylerView必然有它的优点,现就RecylerView相对于ListView的优点罗列如下:

①RecylerView封装了viewholder的回收复用,也就是说RecylerView标准化了ViewHolder,编写Adapter面向的是ViewHolder而不再是View了,复用的 逻辑被封装了,写起来更加简单。

②提供了一种插拔式的体验,高度的解耦,异常的灵活,针对一个Item的显示RecylerView专门抽取出了相应的类,来控制Item的显示,使其的扩展性非常强。例如:你想控制横向或者纵向滑动列表效果可以通过LinearLayoutManager这个类来进行控制(与GridView效果对应的是GridLayoutManager,与瀑布流对应的还有StaggeredGridLayoutManager等),也就是说RecylerView不再拘泥于ListView的线性展示方式,它也可以实现GridView的效果等多种效果。你想控制Item的分隔线,可以通过继承RecylerView的ItemDecoration这个类,然后针对自己的业务需求去抒写代码。

③可以控制Item增删的动画,可以通过ItemAnimator这个类进行控制,当然针对增删的动画,RecylerView有其自己默认的实现。

3.RecyclerView的用法

3.1 RecyclerView的初步用法(包括RecyclerView.Adapter用法)

说了这么多,可能大家最关心的就是RecylerView应该怎么用,我们先来讨论讨论RecylerView的用法的理论知识,然后结合一个实例来体验一下RecylerView的优势首先我们需要明白的一点是使用RecylerView必须导入support-v7包,在上面我提到过RecylerView高度的解耦,异常的灵活谷歌给我们提供了多个类来控制Item的显示。

[java]view plaincopy

可以看到对RecylerView的设置过程,比ListView要复杂一些,这也是RecylerView高度解耦的表现,虽然代码抒写上有点复杂,但它的扩展性是极高的。

[java]view plaincopy

[java]view plaincopy

[java]view plaincopy

可以看到系统给提供的动画效果还不错,当然我们也可以按照业务需求去自己定义动画效果。

3.5 给RecyclerView的Item添加点击事件

到这里还有一点从文章开头到现在我们都没有提及,就是Item的点击事件RecyclerView监听事件处理在ListView使用的时候,该控件给我们提供一个onItemClickListener监听器,这样当我们点击Item的时候,会回调相关的方法,以便我们方便处理Item点击事件。对于RecyclerView来讲,非常可惜的是,该控件没有给我们提供这样的内置监听器方法,不过我们可以进行改造实现,可以这样实现Item的点击事件的监听,在我们的adapter中增加这两个方法

publicinterfaceOnItemClickListener{

voidonClick(intposition);

voidonLongClick(intposition);

}

publicvoidsetOnItemClickListener(OnItemClickListener onItemClickListener ){

this.mOnItemClickListener=onItemClickListener;

}

然后onBindViewHolder方法要做如下更改

[java]view plaincopy

[java]view plaincopy

然后运行,效果如下:

Android开发之RecyclerView的使用

可以看到Item的onClick和onLongClick事件都触发了。到此关于RecyclerView的基本用法就介绍的差不多了,当然,还有几个点没有提到,比方说瀑布流、下拉刷新、上拉加载等,由于篇幅原因这些在后面的更新中都会给大家呈现。最后将本篇博客所提到的知识点做一个整合,写到Demo中,大家可以参考,Demo进行学习。好了,这一篇就到这里了,如果发现什么错误,或者有什么疑问请留言,感谢您的观看,谢谢各位的支持。。。

转载请注明出处:https://blog.csdn.net/dmk877/article/details/50816933

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

LinearLayoutManagerlayoutManager=newLinearLayoutManager(this);

//设置布局管理器

recyclerView.setLayoutManager(layoutManager);

//设置为垂直布局,这也是默认的

layoutManager.setOrientation(OrientationHelper.VERTICAL);

//设置Adapter

recyclerView.setAdapter(recycleAdapter);

//设置分隔线

recyclerView.addItemDecoration(newDividerGridItemDecoration(this));

//设置增加或删除条目的动画

recyclerView.setItemAnimator(newDefaultItemAnimator());

在了解了RecyclerView的一些控制之后,紧接着来看看它的Adapter的写法,RecyclerView的Adapter与ListView的Adapter还是有点区别的,RecyclerView.Adapter,需要实现3个方法:

①onCreateViewHolder()

这个方法主要生成为每个Item inflater出一个View,但是该方法返回的是一个ViewHolder。该方法把View直接封装在ViewHolder中,然后我们面向的是ViewHolder这个实例,当然这个ViewHolder需要我们自己去编写。直接省去了当初的convertView.setTag(holder)和convertView.getTag()这些繁琐的步骤。

②onBindViewHolder()

这个方法主要用于适配渲染数据到View中。方法提供给你了一个viewHolder,而不是原来的convertView。

③getItemCount()

这个方法就类似于BaseAdapter的getCount方法了,即总共有多少个条目。

实例:接着来几个小的实例帮助大家更深入的了解RecyclerView的用法,首先来实现一个最简单的列表,效果如下

Android开发之RecyclerView的使用

这种效果的MainAcitivity的代码如下

packagecom.example.reclerviewpractice;

importjava.util.ArrayList;

importjava.util.List;

importcom.example.reclerviewpractice.adapter.MyRecyclerAdapter;

importandroid.annotation.SuppressLint;

importandroid.os.Bundle;

importandroid.support.v7.app.ActionBarActivity;

importandroid.support.v7.widget.DefaultItemAnimator;

importandroid.support.v7.widget.LinearLayoutManager;

importandroid.support.v7.widget.OrientationHelper;

importandroid.support.v7.widget.RecyclerView;

publicclassMainActivityextendsActionBarActivity{

privateRecyclerViewrecyclerView;

privateListmDatas;

privateMyRecyclerAdapterrecycleAdapter;

@SuppressLint("NewApi")@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

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

initData();

recycleAdapter=newMyRecyclerAdapter(MainActivity.this,mDatas);

LinearLayoutManagerlayoutManager=newLinearLayoutManager(this);

//设置布局管理器

recyclerView.setLayoutManager(layoutManager);

//设置为垂直布局,这也是默认的

layoutManager.setOrientation(OrientationHelper.VERTICAL);

//设置Adapter

recyclerView.setAdapter(recycleAdapter);

//设置增加或删除条目的动画

recyclerView.setItemAnimator(newDefaultItemAnimator());

}

privatevoidinitData(){

mDatas=newArrayList();

for(inti=0;imDatas.add("item"+i);

}

}

}

packagecom.example.reclerviewpractice.adapter;

importjava.util.List;

importcom.example.reclerviewpractice.R;

importandroid.content.Context;

importandroid.support.v7.widget.RecyclerView;

importandroid.support.v7.widget.RecyclerView.ViewHolder;

importandroid.view.LayoutInflater;

importandroid.view.View;

importandroid.view.ViewGroup;

importandroid.widget.TextView;

publicclassMyRecyclerAdapterextendsRecyclerView.Adapter{

privateListmDatas;

privateContextmContext;

privateLayoutInflaterinflater;

publicMyRecyclerAdapter(Contextcontext,Listdatas){

this.mContext=context;

this.mDatas=datas;

inflater=LayoutInflater.from(mContext);

}

@Override

publicintgetItemCount(){

returnmDatas.size();

}

//填充onCreateViewHolder方法返回的holder中的控件

@Override

publicvoidonBindViewHolder(MyViewHolderholder,finalintposition){

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

}

//重写onCreateViewHolder方法,返回一个自定义的ViewHolder

@Override

publicMyViewHolderonCreateViewHolder(ViewGroupparent,intviewType){

Viewview=inflater.inflate(R.layout.item_home,parent,false);

MyViewHolderholder=newMyViewHolder(view);

returnholder;

}

classMyViewHolderextendsViewHolder{

TextViewtv;

publicMyViewHolder(Viewview){

super(view);

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

}

}

}

publicstaticabstractclassItemDecoration{

publicvoidonDraw(Canvasc,RecyclerViewparent,Statestate){

onDraw(c,parent);

}

publicvoidonDrawOver(Canvasc,RecyclerViewparent,Statestate){

onDrawOver(c,parent);

}

publicvoidgetItemOffsets(RectoutRect,Viewview,RecyclerViewparent,Statestate){

getItemOffsets(outRect,((LayoutParams)view.getLayoutParams()).getViewLayoutPosition(),parent);

}

}

packagecom.example.reclerviewpractice;

importandroid.content.Context;

importandroid.content.res.TypedArray;

importandroid.graphics.Canvas;

importandroid.graphics.Rect;

importandroid.graphics.drawable.Drawable;

importandroid.support.v7.widget.LinearLayoutManager;

importandroid.support.v7.widget.RecyclerView;

importandroid.view.View;

publicclassDividerItemDecorationextendsRecyclerView.ItemDecoration{

privatestaticfinalint[]ATTRS=newint[]{

android.R.attr.listDivider

};

publicstaticfinalintHORIZONTAL_LIST=LinearLayoutManager.HORIZONTAL;

publicstaticfinalintVERTICAL_LIST=LinearLayoutManager.VERTICAL;

privateDrawablemDivider;

privateintmOrientation;

publicDividerItemDecoration(Contextcontext,intorientation){

finalTypedArraya=context.obtainStyledAttributes(ATTRS);

mDivider=a.getDrawable(0);

a.recycle();

setOrientation(orientation);

}

publicvoidsetOrientation(intorientation){

if(orientation!=HORIZONTAL_LIST&&orientation!=VERTICAL_LIST){

thrownewIllegalArgumentException("invalidorientation");

}

mOrientation=orientation;

}

@Override

publicvoidonDraw(Canvasc,RecyclerViewparent){

if(mOrientation==VERTICAL_LIST){

drawVertical(c,parent);

}else{

drawHorizontal(c,parent);

}

}

publicvoiddrawVertical(Canvasc,RecyclerViewparent){

finalintleft=parent.getPaddingLeft();

finalintright=parent.getWidth()-parent.getPaddingRight();

finalintchildCount=parent.getChildCount();

for(inti=0;ifinalViewchild=parent.getChildAt(i);

finalRecyclerView.LayoutParamsparams=(RecyclerView.LayoutParams)child

.getLayoutParams();

finalinttop=child.getBottom()+params.bottomMargin;

finalintbottom=top+mDivider.getIntrinsicHeight();

mDivider.setBounds(left,top,right,bottom);

mDivider.draw(c);

}

}

publicvoiddrawHorizontal(Canvasc,RecyclerViewparent){

finalinttop=parent.getPaddingTop();

finalintbottom=parent.getHeight()-parent.getPaddingBottom();

finalintchildCount=parent.getChildCount();

for(inti=0;ifinalViewchild=parent.getChildAt(i);

finalRecyclerView.LayoutParamsparams=(RecyclerView.LayoutParams)child

.getLayoutParams();

finalintleft=child.getRight()+params.rightMargin;

finalintright=left+mDivider.getIntrinsicHeight();

mDivider.setBounds(left,top,right,bottom);

mDivider.draw(c);

}

}

@Override

publicvoidgetItemOffsets(RectoutRect,intitemPosition,RecyclerViewparent){

if(mOrientation==VERTICAL_LIST){

outRect.set(0,0,0,mDivider.getIntrinsicHeight());

}else{

outRect.set(0,0,mDivider.getIntrinsicWidth(),0);

}

}

}

@drawable/pider

修改之后运行效果如下:

Android开发之RecyclerView的使用

可以看到分隔线的颜色变了,当然了这只是一个小例子,我们可以按照业务需求去更改,这样就基本实现了ListView的效果,看到这肯定会有人说,这尼玛,好麻烦,还不如ListView简单呢,从上面的代码量看来确实是使用起来很复杂,但是如果此时你想将这个列表以GridView的形式展示出来,用RecylerView仅仅是换一行代码的事情,

在上面的代码中我们使用了

LinearLayoutManagerlayoutManager=newLinearLayoutManager(this);

//设置布局管理器

recyclerView.setLayoutManager(layoutManager);

recyclerView.setLayoutManager(newGridLayoutManager(this,4));

finalintleft=parent.getPaddingLeft();

finalintright=parent.getWidth()-parent.getPaddingRight();

这两行我们可以看出来,它是绘制了一条线这条线就是从RecyclerView去掉左右边距后,剩余的部分,因为当显示成ListView时每一行就一个Item所以整体效果看上去就跟ListView差不多,而当展示成GridView那样的效果时,每一行就不止一个条目了,而有可能是多个,所以这个类就不再适用了,我们需要重新写一个,这里我就直接用鸿洋大神写的了,它的博客地址:https://blog.csdn.net/lmj623565791/article/details/45059587

packagecom.example.reclerviewpractice;

importandroid.content.Context;

importandroid.content.res.TypedArray;

importandroid.graphics.Canvas;

importandroid.graphics.Rect;

importandroid.graphics.drawable.Drawable;

importandroid.support.v7.widget.GridLayoutManager;

importandroid.support.v7.widget.RecyclerView;

importandroid.support.v7.widget.RecyclerView.LayoutManager;

importandroid.support.v7.widget.RecyclerView.State;

importandroid.support.v7.widget.StaggeredGridLayoutManager;

importandroid.view.View;

/**

*

*@authorzhy

*

*/

publicclassDividerGridItemDecorationextendsRecyclerView.ItemDecoration

{

privatestaticfinalint[]ATTRS=newint[]{android.R.attr.listDivider};

privateDrawablemDivider;

publicDividerGridItemDecoration(Contextcontext)

{

finalTypedArraya=context.obtainStyledAttributes(ATTRS);

mDivider=a.getDrawable(0);

a.recycle();

}

@Override

publicvoidonDraw(Canvasc,RecyclerViewparent,Statestate)

{

drawHorizontal(c,parent);

drawVertical(c,parent);

}

privateintgetSpanCount(RecyclerViewparent)

{

//列数

intspanCount=-1;

LayoutManagerlayoutManager=parent.getLayoutManager();

if(layoutManagerinstanceofGridLayoutManager)

{

spanCount=((GridLayoutManager)layoutManager).getSpanCount();

}elseif(layoutManagerinstanceofStaggeredGridLayoutManager)

{

spanCount=((StaggeredGridLayoutManager)layoutManager)

.getSpanCount();

}

returnspanCount;

}

publicvoiddrawHorizontal(Canvasc,RecyclerViewparent)

{

intchildCount=parent.getChildCount();

for(inti=0;i{

finalViewchild=parent.getChildAt(i);

finalRecyclerView.LayoutParamsparams=(RecyclerView.LayoutParams)child

.getLayoutParams();

finalintleft=child.getLeft()-params.leftMargin;

finalintright=child.getRight()+params.rightMargin

+mDivider.getIntrinsicWidth();

finalinttop=child.getBottom()+params.bottomMargin;

finalintbottom=top+mDivider.getIntrinsicHeight();

mDivider.setBounds(left,top,right,bottom);

mDivider.draw(c);

}

}

publicvoiddrawVertical(Canvasc,RecyclerViewparent)

{

finalintchildCount=parent.getChildCount();

for(inti=0;i{

finalViewchild=parent.getChildAt(i);

finalRecyclerView.LayoutParamsparams=(RecyclerView.LayoutParams)child

.getLayoutParams();

finalinttop=child.getTop()-params.topMargin;

finalintbottom=child.getBottom()+params.bottomMargin;

finalintleft=child.getRight()+params.rightMargin;

finalintright=left+mDivider.getIntrinsicWidth();

mDivider.setBounds(left,top,right,bottom);

mDivider.draw(c);

}

}

privatebooleanisLastColum(RecyclerViewparent,intpos,intspanCount,

intchildCount)

{

LayoutManagerlayoutManager=parent.getLayoutManager();

if(layoutManagerinstanceofGridLayoutManager)

{

if((pos+1)%spanCount==0)//如果是最后一列,则不需要绘制右边

{

returntrue;

}

}elseif(layoutManagerinstanceofStaggeredGridLayoutManager)

{

intorientation=((StaggeredGridLayoutManager)layoutManager)

.getOrientation();

if(orientation==StaggeredGridLayoutManager.VERTICAL)

{

if((pos+1)%spanCount==0)//如果是最后一列,则不需要绘制右边

{

returntrue;

}

}else

{

childCount=childCount-childCount%spanCount;

if(pos>=childCount)//如果是最后一列,则不需要绘制右边

returntrue;

}

}

returnfalse;

}

privatebooleanisLastRaw(RecyclerViewparent,intpos,intspanCount,

intchildCount)

{

LayoutManagerlayoutManager=parent.getLayoutManager();

if(layoutManagerinstanceofGridLayoutManager)

{

childCount=childCount-childCount%spanCount;

if(pos>=childCount)//如果是最后一行,则不需要绘制底部

returntrue;

}elseif(layoutManagerinstanceofStaggeredGridLayoutManager)

{

intorientation=((StaggeredGridLayoutManager)layoutManager)

.getOrientation();

//StaggeredGridLayoutManager且纵向滚动

if(orientation==StaggeredGridLayoutManager.VERTICAL)

{

childCount=childCount-childCount%spanCount;

//如果是最后一行,则不需要绘制底部

if(pos>=childCount)

returntrue;

}else

//StaggeredGridLayoutManager且横向滚动

{

//如果是最后一行,则不需要绘制底部

if((pos+1)%spanCount==0)

{

returntrue;

}

}

}

returnfalse;

}

@Override

publicvoidgetItemOffsets(RectoutRect,intitemPosition,

RecyclerViewparent)

{

intspanCount=getSpanCount(parent);

intchildCount=parent.getAdapter().getItemCount();

if(isLastRaw(parent,itemPosition,spanCount,childCount))//如果是最后一行,则不需要绘制底部

{

outRect.set(0,0,mDivider.getIntrinsicWidth(),0);

}elseif(isLastColum(parent,itemPosition,spanCount,childCount))//如果是最后一列,则不需要绘制右边

{

outRect.set(0,0,0,mDivider.getIntrinsicHeight());

}else

{

outRect.set(0,0,mDivider.getIntrinsicWidth(),

mDivider.getIntrinsicHeight());

}

}

}

StaggeredGridLayoutManagerlayoutManager=newStaggeredGridLayoutManager(4,StaggeredGridLayoutManager.HORIZONTAL);

//设置布局管理器

recyclerView.setLayoutManager(layoutManager);

LinearLayoutManagerlayoutManager=newLinearLayoutManager(this);

//设置布局管理器

recyclerView.setLayoutManager(layoutManager);

//设置增加或删除条目的动画

recyclerView.setItemAnimator(newDefaultItemAnimator());

@Override

publicbooleanonCreateOptionsMenu(Menumenu)

{

getMenuInflater().inflate(R.menu.main,menu);

returnsuper.onCreateOptionsMenu(menu);

}

@Override

publicbooleanonOptionsItemSelected(MenuItemitem)

{

switch(item.getItemId())

{

caseR.id.id_action_add:

recycleAdapter.addData(1);

break;

caseR.id.id_action_delete:

recycleAdapter.removeData(1);

break;

}

returntrue;

}

publicfinalvoidnotifyDataSetChanged()

publicfinalvoidnotifyItemChanged(intposition)

publicfinalvoidnotifyItemRangeChanged(intpositionStart,intitemCount)

publicfinalvoidnotifyItemInserted(intposition)

publicfinalvoidnotifyItemMoved(intfromPosition,inttoPosition)

publicfinalvoidnotifyItemRangeInserted(intpositionStart,intitemCount)

publicfinalvoidnotifyItemRemoved(intposition)

publicfinalvoidnotifyItemRangeRemoved(intpositionStart,intitemCount)

notifyDataSetChanged()这个方法跟我们平时用到的ListView的Adapter的方法一样,这里就不多做描述了。

notifyItemChanged(int position),当position位置的数据发生了改变时就会调用这个方法,就会回调对应position的onBindViewHolder()方法了,当然,因为ViewHolder是复用的,所以如果position在当前屏幕以外,也就不会回调了,因为没有意义,下次position滚动会当前屏幕以内的时候同样会调用onBindViewHolder()方法刷新数据了。其他的方法也是同样的道理。public final void notifyItemRangeChanged(int positionStart, int itemCount),顾名思义,可以刷新从positionStart开始itemCount数量的item了(这里的刷新指回调onBindViewHolder()方法)。

public final void notifyItemInserted(int position),这个方法是在第position位置被插入了一条数据的时候可以使用这个方法刷新,注意这个方法调用后会有插入的动画,这个动画可以使用默认的,也可以自己定义。

public final void notifyItemMoved(int fromPosition, int toPosition),这个方法是从fromPosition移动到toPosition为止的时候可以使用这个方法刷新

public final void notifyItemRangeInserted(int positionStart, int itemCount),显然是批量添加。

public final void notifyItemRemoved(int position),第position个被删除的时候刷新,同样会有动画。

将上述更改运行,点击添加和删除按钮效果图如下:

public final void notifyItemRangeRemoved(int positionStart, int itemCount),批量删除。

Android开发之RecyclerView的使用

@Override

publicvoidonBindViewHolder(MyViewHolderholder,finalintposition){

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

if(mOnItemClickListener!=null){

holder.itemView.setOnClickListener(newOnClickListener(){

@Override

publicvoidonClick(Viewv){

mOnItemClickListener.onClick(position);

}

});

holder.itemView.setOnLongClickListener(newOnLongClickListener(){

@Override

publicbooleanonLongClick(Viewv){

mOnItemClickListener.onLongClick(position);

returnfalse;

}

});

}

}

在MainAcitivity中增加

recycleAdapter.setOnItemClickListener(newOnItemClickListener(){

@Override

publicvoidonLongClick(intposition){

Toast.makeText(MainActivity.this,"onLongClick事件您点击了第:"+position+"个Item",0).show();

}

@Override

publicvoidonClick(intposition){

Toast.makeText(MainActivity.this,"onClick事件您点击了第:"+position+"个Item",0).show();

}

});