我的编程空间,编程开发者的网络收藏夹
学习永远不晚

谈谈Android开发之RecyclerView的使用全解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

谈谈Android开发之RecyclerView的使用全解

自Android 5.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的显示。


recyclerView = (RecyclerView) findViewById(R.id.recyclerView); 
LinearLayoutManager layoutManager = new LinearLayoutManager(this ); 
//设置布局管理器 
recyclerView.setLayoutManager(layoutManager); 
//设置为垂直布局,这也是默认的 
layoutManager.setOrientation(OrientationHelper. VERTICAL); 
//设置Adapter 
recyclerView.setAdapter( recycleAdapter); 
 //设置分隔线 
recyclerView.addItemDecoration( new DividerGridItemDecoration(this )); 
//设置增加或删除条目的动画 
recyclerView.setItemAnimator( new DefaultItemAnimator()); 

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

在了解了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的用法,首先来实现一个最简单的列表,效果如下

这种效果的MainAcitivity的代码如下


package com.example.reclerviewpractice; 
import java.util.ArrayList; 
import java.util.List; 
import com.example.reclerviewpractice.adapter.MyRecyclerAdapter; 
import android.annotation.SuppressLint; 
import android.os.Bundle; 
import android.support.v7.app.ActionBarActivity; 
import android.support.v7.widget.DefaultItemAnimator; 
import android.support.v7.widget.LinearLayoutManager; 
import android.support.v7.widget.OrientationHelper; 
import android.support.v7.widget.RecyclerView; 
public class MainActivity extends ActionBarActivity { 
   private RecyclerView recyclerView; 
   private List<String> mDatas; 
   private MyRecyclerAdapter recycleAdapter; 
   @SuppressLint("NewApi") @Override 
   protected void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      setContentView(R.layout. activity_main); 
      recyclerView = (RecyclerView) findViewById(R.id.recyclerView ); 
      initData(); 
      recycleAdapter= new MyRecyclerAdapter(MainActivity.this , mDatas ); 
      LinearLayoutManager layoutManager = new LinearLayoutManager(this); 
      //设置布局管理器 
      recyclerView.setLayoutManager(layoutManager); 
      //设置为垂直布局,这也是默认的 
      layoutManager.setOrientation(OrientationHelper.VERTICAL); 
      //设置Adapter 
      recyclerView.setAdapter( recycleAdapter); 
      //设置增加或删除条目的动画 
      recyclerView.setItemAnimator(new DefaultItemAnimator()); 
   } 
   private void initData() { 
      mDatas = new ArrayList<String>(); 
      for ( int i=0; i < 40; i++) { 
         mDatas.add( "item"+i); 
      } 
   } 
} 

RecyclerView的Adapter的代码如下:


package com.example.reclerviewpractice.adapter; 
import java.util.List; 
import com.example.reclerviewpractice.R; 
import android.content.Context; 
import android.support.v7.widget.RecyclerView; 
import android.support.v7.widget.RecyclerView.ViewHolder; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.TextView; 
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.MyViewHolder> { 
   private List<String> mDatas; 
   private Context mContext; 
   private LayoutInflater inflater; 
   public MyRecyclerAdapter(Context context, List<String> datas){ 
      this. mContext=context; 
      this. mDatas=datas; 
      inflater=LayoutInflater. from(mContext); 
   } 
   @Override 
   public int getItemCount() { 
      return mDatas.size(); 
   } 
   //填充onCreateViewHolder方法返回的holder中的控件 
   @Override 
   public void onBindViewHolder(MyViewHolder holder, final int position) { 
      holder.tv.setText( mDatas.get(position)); 
   } 
   //重写onCreateViewHolder方法,返回一个自定义的ViewHolder 
   @Override 
   public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
      View view = inflater.inflate(R.layout. item_home,parent, false); 
      MyViewHolder holder= new MyViewHolder(view); 
      return holder; 
   } 
   class MyViewHolder extends ViewHolder{ 
      TextView tv; 
      public MyViewHolder(View view) { 
         super(view); 
         tv=(TextView) view.findViewById(R.id. tv_item); 
      } 
   } 
} 

可以看到RecyclerView标准化了ViewHolder,编写 Adapter面向的是ViewHoder而不在是View了,复用的逻辑被封装了,写起来更加简单。其实它的写法与BaseAdapter的写法是差不多的,大家可以对比下它与getView方法写法的区别,在onCreateViewHolder方法中初始化了一个View,然后返回一个ViewHolder,这个返回的ViewHolder类似于之前在getView中的convertView.getTag(),然后在onBindViewHolder方法中去给这个ViewHolder中的控件填充值。其实它的原理跟getView是差不多的,只是做了封装,我们写起来比较简洁。到这里,看到上述运行效果可能有很多人会说,这效果太丑了,连个分隔线都没有,不要急,我们一步一步来。

 3.2 RecyclerView增加分隔线

前面我们说到可以通过RecyclerView.addItemDecoration(ItemDecoration decoration)这个方法进行设置,其中它需要的参数就是我们自己定义的继承自ItemDecoration的一个对象。我们可以创建一个继承RecyclerView.ItemDecoration类来绘制分隔线,通过ItemDecoration可以让我们每一个Item从视觉上面相互分开来,例如ListView的divider非常相似的效果。当然像我们上面的例子ItemDecoration我们没有设置也没有报错,那说明ItemDecoration我们并不是强制需要使用,作为我们开发者可以设置或者不设置Decoration的。实现一个ItemDecoration,系统提供的ItemDecoration是一个抽象类,内部除去已经废弃的方法以外,我们主要实现以下三个方法:


public static abstract class ItemDecoration {  
    public void onDraw(Canvas c,RecyclerView parent,State state) {  
     onDraw(c,parent);  
   }  
   public void onDrawOver(Canvas c,RecyclerView parent,State state) {  
     onDrawOver(c,parent);  
   }  
   public void getItemOffsets(RectoutRect, View view,RecyclerView parent,State state) {  
     getItemOffsets(outRect,((LayoutParams)view.getLayoutParams()).getViewLayoutPosition(),parent);  
   }  
 } 

又因为当我们RecyclerView在进行绘制的时候会进行绘制Decoration,那么会去调用onDraw和onDrawOver方法,那么这边我们其实只要去重写onDraw和getItemOffsets这两个方法就可以实现啦。然后LayoutManager会进行Item布局的时候,会去调用getItemOffset方法来计算每个Item的Decoration合适的尺寸,下面我们来具体实现一个Decoration,DividerItemDecoration.Java


package com.example.reclerviewpractice; 
import android.content.Context; 
import android.content.res.TypedArray; 
import android.graphics.Canvas; 
import android.graphics.Rect; 
import android.graphics.drawable.Drawable; 
import android.support.v7.widget.LinearLayoutManager ; 
import android.support.v7.widget.RecyclerView; 
import android.view.View; 
public class DividerItemDecoration extends RecyclerView.ItemDecoration { 
  private static final int[] ATTRS = new int[]{ 
      android.R.attr. listDivider 
  }; 
  public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; 
  public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; 
  private Drawable mDivider; 
  private int mOrientation; 
  public DividerItemDecoration(Context context, int orientation) { 
    final TypedArray a = context.obtainStyledAttributes(ATTRS ); 
    mDivider = a.getDrawable(0); 
    a.recycle(); 
    setOrientation(orientation); 
  } 
  public void setOrientation( int orientation) { 
    if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { 
      throw new IllegalArgumentException( "invalid orientation"); 
    } 
    mOrientation = orientation; 
  } 
  @Override 
  public void onDraw(Canvas c, RecyclerView parent) { 
    if (mOrientation == VERTICAL_LIST) { 
      drawVertical(c, parent); 
    } else { 
      drawHorizontal(c, parent); 
    } 
  } 
  public void drawVertical(Canvas c, RecyclerView parent) { 
    final int left = parent.getPaddingLeft(); 
    final int right = parent.getWidth() - parent.getPaddingRight(); 
    final int childCount = parent.getChildCount(); 
    for (int i = 0; i < childCount; i++) { 
      final View child = parent.getChildAt(i); 
      final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 
          .getLayoutParams(); 
      final int top = child.getBottom() + params.bottomMargin; 
      final int bottom = top + mDivider.getIntrinsicHeight(); 
      mDivider.setBounds(left, top, right, bottom); 
      mDivider.draw(c); 
    } 
  } 
  public void drawHorizontal(Canvas c, RecyclerView parent) { 
    final int top = parent.getPaddingTop(); 
    final int bottom = parent.getHeight() - parent.getPaddingBottom(); 
    final int childCount = parent.getChildCount(); 
    for (int i = 0; i < childCount; i++) { 
      final View child = parent.getChildAt(i); 
      final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 
          .getLayoutParams(); 
      final int left = child.getRight() + params.rightMargin; 
      final int right = left + mDivider.getIntrinsicHeight(); 
      mDivider.setBounds(left, top, right, bottom); 
      mDivider.draw(c); 
    } 
  } 
  @Override 
  public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { 
    if (mOrientation == VERTICAL_LIST) { 
      outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); 
    }else{ 
      outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); 
    } 
  } 
} 

在这里我们采用系统主题(android.R.attr.listDivider)来设置成分隔线的,然后来获取尺寸,位置进行setBound(),绘制,接着通过outRect.set()来设置绘制整个区域范围,当然了它是有两种情况的一种LinearLayoutManager.HORIZONTAL另外一种LinearLayoutManager.VERTICAL需要分别对其进行处理,最后不要忘记往RecyclerView中设置该自定义的分割线,然后在MainActivity中加上一句recyclerView .addItemDecoration(new DividerItemDecoration(MainActivity.this,LinearLayoutManager.VERTICAL))即给RecyclerView增加分隔线。然后运行,效果如下:

可以看到已经有了分隔线,跟ListView的效果基本一致了。当然了,既然谷歌给我们提供了这个专门添加分隔线的方法,那它肯定会允许我们自定义分隔线的样式,不然把这个方法抽取出来也没有任何意义。

  3.3 改变分隔线样式

那么怎么更改分隔线的样式呢?在上面的DividerItemDecoration这个类中可以看到这个分隔线是跟ListView一样的,即系统的默认的样式,因此我们可以在styles的xml文件中进行更改,更改如下:


<!-- Application theme. --> 
  <style name ="AppTheme" parent="AppBaseTheme"> 
    <!-- All customizations that are NOT specific to a particular API-level can go here. --> 
    <item name= "android:listDivider">@drawable/divider </item >  
  </style > 

divider的内容如下:


<?xml version="1.0" encoding= "utf-8"?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
  android:shape="rectangle" > 
    <!-- 填充的颜色 --> 
    <solid android:color ="@color/color_red"/> 
   <!-- 线条大小 --> 
   <size android:height ="1dp" android:width ="1dp"/> 
</shape> 

修改之后运行效果如下:

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


LinearLayoutManager layoutManager = new LinearLayoutManager(this); 
 //设置布局管理器 
recyclerView.setLayoutManager(layoutManager); 

RecyclerView.LayoutManager是一个抽象类,系统为我们提供了三个实现类

①LinearLayoutManager即线性布局,这个是在上面的例子中我们用到的布局

②GridLayoutManager即表格布局

③StaggeredGridLayoutManager即流式布局,如瀑布流效果

假如将上述例子换成GridView的效果,那么相应的代码应该这样改


recyclerView .setLayoutManager(new GridLayoutManager( this,4)); 

除此之外上述的分隔线也要做相应的更改,因为在上述DividerItemDecoration这个方法中从


final int left = parent.getPaddingLeft(); 
final int right = parent.getWidth() - parent.getPaddingRight(); 

这两行我们可以看出来,它是绘制了一条线这条线就是从RecyclerView去掉左右边距后,剩余的部分,因为当显示成ListView时每一行就一个Item所以整体效果看上去就跟ListView差不多,而当展示成GridView那样的效果时,每一行就不止一个条目了,而有可能是多个,所以这个类就不再适用了,我们需要重新写一个。


package com.example.reclerviewpractice;  
import android.content.Context; 
import android.content.res.TypedArray; 
import android.graphics.Canvas; 
import android.graphics.Rect; 
import android.graphics.drawable.Drawable; 
import android.support.v7.widget.GridLayoutManager; 
import android.support.v7.widget.RecyclerView; 
import android.support.v7.widget.RecyclerView.LayoutManager; 
import android.support.v7.widget.RecyclerView.State; 
import android.support.v7.widget.StaggeredGridLayoutManager; 
import android.view.View; 
 
public class DividerGridItemDecoration extends RecyclerView.ItemDecoration 
{ 
   private static final int[] ATTRS = new int[] { android.R.attr.listDivider }; 
   private Drawable mDivider; 
   public DividerGridItemDecoration(Context context) 
   { 
      final TypedArray a = context.obtainStyledAttributes(ATTRS ); 
      mDivider = a.getDrawable(0); 
      a.recycle(); 
   } 
   @Override 
   public void onDraw(Canvas c, RecyclerView parent, State state) 
   { 
      drawHorizontal(c, parent); 
      drawVertical(c, parent); 
   } 
   private int getSpanCount(RecyclerView parent) 
   { 
      // 列数 
      int spanCount = -1; 
      LayoutManager layoutManager = parent.getLayoutManager(); 
      if (layoutManager instanceof GridLayoutManager) 
      { 
        spanCount = ((GridLayoutManager) layoutManager).getSpanCount(); 
      } else if (layoutManager instanceof StaggeredGridLayoutManager) 
      { 
        spanCount = ((StaggeredGridLayoutManager) layoutManager) 
              .getSpanCount(); 
      } 
      return spanCount; 
   } 
   public void drawHorizontal(Canvas c, RecyclerView parent) 
   { 
      int childCount = parent.getChildCount(); 
      for ( int i = 0; i < childCount; i++) 
      { 
         final View child = parent.getChildAt(i); 
         final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 
              .getLayoutParams(); 
         final int left = child.getLeft() - params.leftMargin; 
         final int right = child.getRight() + params.rightMargin 
              + mDivider.getIntrinsicWidth(); 
         final int top = child.getBottom() + params.bottomMargin; 
         final int bottom = top + mDivider.getIntrinsicHeight(); 
         mDivider.setBounds(left, top, right, bottom); 
         mDivider.draw(c); 
      } 
   } 
   public void drawVertical(Canvas c, RecyclerView parent) 
   { 
      final int childCount = parent.getChildCount(); 
      for ( int i = 0; i < childCount; i++) 
      { 
         final View child = parent.getChildAt(i); 
         final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 
              .getLayoutParams(); 
         final int top = child.getTop() - params.topMargin; 
         final int bottom = child.getBottom() + params.bottomMargin; 
         final int left = child.getRight() + params.rightMargin; 
         final int right = left + mDivider.getIntrinsicWidth(); 
         mDivider.setBounds(left, top, right, bottom); 
         mDivider.draw(c); 
      } 
   } 
   private boolean isLastColum(RecyclerView parent, int pos, int spanCount, 
         int childCount) 
   { 
      LayoutManager layoutManager = parent.getLayoutManager(); 
      if (layoutManager instanceof GridLayoutManager) 
      { 
         if ((pos + 1) % spanCount == 0) // 如果是最后一列,则不需要绘制右边 
        { 
           return true; 
        } 
      } else if (layoutManager instanceof StaggeredGridLayoutManager) 
      { 
         int orientation = ((StaggeredGridLayoutManager) layoutManager) 
              .getOrientation(); 
         if (orientation == StaggeredGridLayoutManager.VERTICAL ) 
        { 
           if ((pos + 1) % spanCount == 0) // 如果是最后一列,则不需要绘制右边 
           { 
              return true; 
           } 
        } else 
        { 
           childCount = childCount - childCount % spanCount; 
           if (pos >= childCount) // 如果是最后一列,则不需要绘制右边 
              return true; 
        } 
      } 
      return false; 
   } 
   private boolean isLastRaw(RecyclerView parent, int pos, int spanCount, 
         int childCount) 
   { 
      LayoutManager layoutManager = parent.getLayoutManager(); 
      if (layoutManager instanceof GridLayoutManager) 
      { 
        childCount = childCount - childCount % spanCount; 
         if (pos >= childCount) // 如果是最后一行,则不需要绘制底部 
           return true; 
      } else if (layoutManager instanceof StaggeredGridLayoutManager) 
      { 
         int orientation = ((StaggeredGridLayoutManager) layoutManager) 
              .getOrientation(); 
         // StaggeredGridLayoutManager 且纵向滚动 
         if (orientation == StaggeredGridLayoutManager.VERTICAL ) 
        { 
           childCount = childCount - childCount % spanCount; 
           // 如果是最后一行,则不需要绘制底部 
           if (pos >= childCount) 
              return true; 
        } else 
         // StaggeredGridLayoutManager 且横向滚动 
        { 
           // 如果是最后一行,则不需要绘制底部 
           if ((pos + 1) % spanCount == 0) 
           { 
              return true; 
           } 
        } 
      } 
      return false; 
   } 
   @Override 
   public void getItemOffsets(Rect outRect, int itemPosition, 
        RecyclerView parent) 
   { 
      int spanCount = getSpanCount(parent); 
      int childCount = parent.getAdapter().getItemCount(); 
      if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部 
      { 
        outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); 
      } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边 
      { 
        outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); 
      } else 
      { 
        outRect.set(0, 0, mDivider.getIntrinsicWidth(), 
              mDivider.getIntrinsicHeight()); 
      } 
   } 
} 

别忘了更改分隔线recyclerView .addItemDecoration(new DividerGridItemDecoration(this ));之后运行发现效果如下

可以看到如果你准备好了分隔线的这个类,从ListView效果到GridView效果,只需要几行代码,是不是瞬间感觉高大上了?还有更让人瞠目结舌的效果,将上述代码做如下更改


StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.HORIZONTAL); 
//设置布局管理器 
recyclerView.setLayoutManager(layoutManager); 

这里需要注意的是StaggeredGridLayoutManager构造的第二个参数传一个orientation,如果传入的是StaggeredGridLayoutManager.VERTICAL那么前面那个参数就代表有多少列;如果传是StaggeredGridLayoutManager.HORIZONTAL那么前面那个参数就代表有多少行

运行效果如下

这效果是不是有点逆天?可以看到,固定为4行,变成了左右滑动。有一点需要注意,如果是横向的时候,item的宽度需要注意去设置,毕竟横向的宽度没有约束了,因为控件可以横向滚动了,另外它还可以实现瀑布流的效果,关于瀑布流我准备后面专门写一篇博客。

 3.4 RecyclerView增加和删除的动画(包括RecyclerView.Adapter中刷新的几个方法的对比)

在上面也提到了控制RecyclerView增加和删除的动画是通过ItemAnimator这个类来实现的,ItemAnimator这类也是个抽象的类,系统默认给我们提供了一种增加和删除的动画,下面我们就来看看这种动画的效果,我们需要做的修改如下:


LinearLayoutManager layoutManager = new LinearLayoutManager(this); 
 //设置布局管理器 
recyclerView.setLayoutManager(layoutManager); 
//设置增加或删除条目的动画 
recyclerView.setItemAnimator( new DefaultItemAnimator()); 

然后重写ActionBar的


@Override 
   public boolean onCreateOptionsMenu(Menu menu) 
   { 
      getMenuInflater().inflate(R.menu. main, menu); 
      return super.onCreateOptionsMenu(menu); 
   } 
   @Override 
   public boolean onOptionsItemSelected(MenuItem item) 
   { 
      switch (item.getItemId()) 
      { 
      case R.id. id_action_add: 
         recycleAdapter.addData(1); 
         break; 
      case R.id. id_action_delete: 
         recycleAdapter.removeData(1); 
         break; 
      } 
      return true; 
   } 

关于R.menu. main中的main.xml这个文件代码就不贴了,在最后的一个汇总的例子里会有
recyclerViewAdapter中增加的两个方法:


public void addData( int position) {
     mDatas.add(position, "Insert One");
     notifyItemInserted(position);
     notifyItemRangeChanged(position, mDatas.size());
   }
   public void removeData( int position) {
     mDatas.remove(position);
     notifyItemRemoved(position);
     notifyItemRangeChanged(position, mDatas.size());
   }

这里需要说一下RecyclerView.Adapter中刷新数据的几个方法,一共有这么几个方法


public final void notifyDataSetChanged() 
public final void notifyItemChanged(int position) 
public final void notifyItemRangeChanged(int positionStart, int itemCount) 
public final void notifyItemInserted(int position)  
public final void notifyItemMoved(int fromPosition, int toPosition) 
public final void notifyItemRangeInserted(int positionStart, int itemCount) 
public final void notifyItemRemoved(int position) 
public final void notifyItemRangeRemoved(int positionStart, int itemCount) 

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),批量删除。

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

3.5 给RecyclerView的Item添加点击事件

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


public interface OnItemClickListener{
    void onClick( int position);
    void onLongClick( int position);
   }
public void setOnItemClickListener(OnItemClickListener onItemClickListener ){
    this. mOnItemClickListener=onItemClickListener;
   }

然后onBindViewHolder方法要做如下更改


@Override 
   public void onBindViewHolder(MyViewHolder holder, final int position) { 
      holder. tv.setText( mDatas.get(position)); 
      if( mOnItemClickListener!= null){ 
        holder. itemView.setOnClickListener( new OnClickListener() { 
           @Override 
           public void onClick(View v) { 
              mOnItemClickListener.onClick(position); 
           } 
        }); 
        holder. itemView.setOnLongClickListener( new OnLongClickListener() { 
           @Override 
           public boolean onLongClick(View v) { 
              mOnItemClickListener.onLongClick(position); 
              return false; 
           } 
        }); 
      } 
   }<span style="color:#333333;"> 
</span> 

在MainAcitivity中增加


recycleAdapter.setOnItemClickListener(new OnItemClickListener() { 
       @Override 
       public void onLongClick(int position) { 
          Toast.makeText(MainActivity.this,"onLongClick事件    您点击了第:"+position+"个Item",0).show(); 
       } 
       @Override 
       public void onClick(int position) { 
          Toast.makeText(MainActivity.this,"onClick事件    您点击了第:"+position+"个Item",0).show(); 
       } 
     }); 

然后运行,效果如下:

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

源码下载:demo

您可能感兴趣的文章:Android RecyclerView 上拉加载更多及下拉刷新功能的实现方法Android RecyclerView加载不同布局简单实现Android中RecyclerView实现横向滑动代码Android中RecyclerView点击Item设置事件Android中RecyclerView布局代替GridView实现类似支付宝的界面Android RecyclerView添加头部和底部的方法Android RecyclerView实现下拉刷新和上拉加载Android中使用RecyclerView实现下拉刷新和上拉加载Android项目实战之仿网易新闻的页面(RecyclerView )Android RecyclerView下拉刷新和上拉加载更多Android基于RecyclerView实现高亮搜索列表


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

谈谈Android开发之RecyclerView的使用全解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

谈谈Android开发之RecyclerView的使用全解

自Android 5.0之后,谷歌公司推出了RecylerView控件,RecylerView,我想看到一个新名词后大部分人会首先发出一个疑问,recylerview是什么?为什么会有recylerview也就是说recylerview的优
2022-06-06

浅谈Android开发Webview的Loading使用效果

这篇文章主要为大家介绍了浅谈Android开发Webview的Loading使用效果详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-02-02

Android开发 - RecyclerView的使用

RecyclerView简单布局的使用 代码部分 RcvClickActivity.java package com.haocent.android.recyclerview.click; import android.os.Bundle;
2022-06-06

学习Android开发之RecyclerView使用初探

在进行一些MaterialDesign规范开发的时候,比如之前说到的CoordinateLayout实现的向上折叠效果的时候,如果依然使用ListView,那么这种效果是做不出来的,因为ListView不兼容这个控件,而替代它的就是Recy
2022-06-06

Android开发之DiffUtil的使用详解

写在前面的话 DiffUtil是一个查找集合变化的工具类,是搭配RecyclerView一起使用的,如果你还不了解RecyclerView,可以阅读一些资料,这里就不介绍了。 先放效果图:可以看到,当我们点击按钮的时候,这个Recycler
2022-06-06

Android开发之ContentProvider的使用详解

前言 Content Provider为存储数据和获取数据提供了统一的接口,它可以完成在不同应用程序下的数据共享,而在上一篇文章Android开发之SQLite的使用方法讲到的SQLite只能在同一个程序中共享数据。另外an
2022-06-06

Android开发之ImageLoader使用详解

先给大家展示效果图,看看是大家想要的效果吗,如果还满意,请参考以下代码:前言 UniversalImageLoader是用于加载图片的一个开源项目,在其项目介绍中是这么写的, 支持多线程图片加载 提供丰富的细节配置,比如线程池大小,HTPP
2022-06-06

Android App开发中使用RecyclerView替代ListView的实践

RecyclerView是Android 5.0的新特性,可以直接代替ListView与GridView,并且能够实现瀑布流的布局,感觉RecyclerView使用的好处就是它不关心布局,只关心资源的回收与复用,正因为如此,Recycler
2022-06-06

Android开发中RecyclerView组件使用的一些进阶技讲解

RecyclerView的优势:它自带ViewHolder来实现View的复用机制,再也不用ListView那样在getView()里自己写了使用LayoutManager可以实现ListView,GridView以及流式布局的列表效果通过
2022-06-06

Android开发之PreferenceActivity的使用

PreferenceActivity是Android中的一个特殊的Activity,用于展示和管理应用程序的偏好设置。通过PreferenceActivity,开发者可以很方便地创建一个设置界面,并将用户的偏好设置保存到SharedPref
2023-09-28

Android开发:浅谈MVP模式应用与内存泄漏问题解决

最近博主开始在项目中实践MVP模式,却意外发现内存泄漏比较严重,但却很少人谈到这个问题,促使了本文的发布,本文假设读者已了解MVP架构。MVP简介 M-Modle,数据,逻辑操作层,数据获取,数据持久化保存。比如网络操作,数据库操作 V-V
2022-06-06

Android App开发中RecyclerView控件的基本使用教程

概述 RecyclerView出现已经有一段时间了,相信大家肯定不陌生了,大家可以通过导入support-v7对其进行使用。 据官方的介绍,该控件用于在有限的窗口中展示大量数据集,其实这样功能的控件我们并不陌生,例如:ListView、G
2022-06-06

Android RecyclerView艺术般的控件使用完全解析

RecyclerView出现已经有一段时间了,相信大家肯定不陌生了,大家可以通过导入support-v7对其进行使用。 据官方的介绍,该控件用于在有限的窗口中展示大量数据集,其实这样功能的控件我们并不陌生,例如:ListView、Grid
2022-06-06

Android开发之XML文件解析的使用

前言 本文主要介绍在Android中怎样来解析XML文件。主要采用的是SAX机制,SAX全称为Simple API for XML,它既是一种接口,也是一个软件包。作为接口,SAX是事件驱动型XML解析的一个标准接口。XML文件解析一般有2
2022-06-06

Android开发之WebView组件的使用解析

在 Android 手机中内置了一款高性能 webkit 内核浏览器, SDK 中封装为一个叫做 WebView 组件。 WebView 类是 WebKit 模块 Java 层的视图类,( 所有需要使用 Web 浏览功能的Android应用
2022-06-06

Android开发笔记之:Dialog的使用详解

Dialog是任何系统都必须有的一个控件,作为辅助窗口,用于显示一些消息,或请求用户采取一引起操作等。在Android中也不例外,基本使用可能参看文档。使用时的注意事项1. BACK键能取消掉对话框(dismiss),但是却不会触发其onO
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录