那年的RecyclerView我们从头撸一下

1. RecyclerView是什么?

创新互联-专业网站定制、快速模板网站建设、高性价比芒康网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式芒康网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖芒康地区。费用合理售后完善,10年实体公司更值得信赖。

根据Google官方给出的说明:A flexible view for providing a limited window into a large data set。能够在有限的窗口中展示大数据集合的灵活视图。

所以我们能够理解为,RecyclerView的一个恰当的使用场景是:由于尺寸限制,用户的设备不能一次性展现所有条目,用户需要上下滚动以查看更多条目。滚出可见区域的条目将被回收,并在下一个条目可见的时候被复用。

对于减少内存开销和CPU的计算,缓存条目是一个非常有用的方法,因为这意味着我们不必每次都创建新的条目,从而减小内存开销和CPU的计算,而且还能够有效降低屏幕的卡顿,保证滑动的顺滑。

RecyclerView不关心视觉效果(visuals)

但是和ListView有什么区别呀?我们已经使用ListView很长一段时间了呀,它一样可以做到呀。从它的类名上看,RecyclerView代表的意义是,我只管Recycler View,也就是说RecyclerView只管回收与复用View,其他的开发者可以自己去设置。你想要另一个布局?插入另一个LayoutManager。你想要不同的动画吗?插入一个ItemAnimator,等等。可以看出其高度的解耦,给予你充分的定制自由(所以你才可以轻松的通过这个控件实现ListView,GirdView,瀑布流等效果)。

2. 引入RecyclerView

RecyclerView 是Support Library的一部分。所以只需要在app/build.gradle中添加以下依赖,便能立即使用:

 
 
 
 
  1. dependencies { compile 'com.android.support:recyclerview-v7:25.3.1'}

在布局文件中加入:

 
 
 
 
  1. android:id="@+id/recycler_view"
  2. android:layout_width="match_parent"
  3. android:layout_height="match_parent" /> 

然后在页面中引入RecyclerView即可:

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

OK,从现在开始,让我们一步一步,开始了解它。

3. 使用RecyclerView

下面的表格中就是使用RecyclerView来显示数据中用到的几个最重要的类,这些类都是RecyclerView的内部类,如果你想使用RecyclerView,需要做以下操作:

Class 功能
Adapter 处理数据集合并负责绑定视图
ViewHolder 持有所有的用于绑定数据或者需要操作的View
LayoutManager 负责摆放视图等相关操作
ItemDecoration 负责绘制Item附近的分割线
ItemAnimator 为Item的一般操作添加动画效果,如,增删条目等

我们可以从下图更直观的了解到RecyclerView的基本结构:

接下来,我将要描述每个类或接口的内容以及如何使用它。

3.1 RecyclerView.ViewHolder

ViewHolder的基本用法是用来存放View对象。Android团队很早之前就推荐使用“ViewHolder设计模式”,但是没有要求开发者在Adapter中必须使用ViewHolder模式。那么现在对于这种新型的RecyclerView.Adapter,我们必须实现并使用这种模式。

Google官方等了这么长时间才强制使用ViewHolder模式,这有点奇怪,但迟做总比不做好。如果您不了解ViewHolder模式,请查看一下Android training Hold View Objects in a View Holder。另外网上有大量关于ListView优化的文章。面试重点。

有一件事是专门针对RecyclerView的。ViewHolder子类可以通过访问公共成员itemView来访问ViewHolder的根视图。所以不需要在ViewHolder子类中存储。

下面是示例的ViewHolder的代码,ViewHolder是示例Adapter的内部类:

 
 
 
 
  1. public static class MyViewHolder extends RecyclerView.ViewHolder{        
  2.        TextView tv;
  3.        public MyViewHolder(View itemView) {            
  4.            super(itemView);
  5.            tv = (TextView) itemView.findViewById(R.id.tv);
  6.        }
  7.    } 

3.2 Adapter

Adapter扮演着两个角色。一是,根据不同ViewType创建与之相应的的Item-Layout,二是,访问数据集合并将数据绑定到正确的View上。这就需要我们重写以下3个方法:

  • public VH onCreateViewHolder(ViewGroup parent, int viewType) 创建Item视图,并返回相应的ViewHolder
  • public void onBindViewHolder(VH holder, int position) 绑定数据到正确的Item视图上。
  • public int getItemCount() 返回该Adapter所持有的item数量

示例代码如下所示:

 
 
 
 
  1. @Override
  2.     public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
  3.         MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context)
  4.                 .inflate(R.layout.item_recycler_view,parent,false));        
  5.                 return holder;
  6.     }    
  7.     @Override
  8.     public void onBindViewHolder(MyViewHolder holder, int position) {
  9.         holder.tv.setText(mDatas.get(position));
  10.     }    
  11.     @Override
  12.     public int getItemCount() {        
  13.         return mDatas.size();
  14.     } 

因此,一个基本的RecyclerView.Adapter如下:

 
 
 
 
  1. public class RecyclerAdapter extends RecyclerView.Adapter {    
  2.     private Context context;    
  3.     private List mDatas;
  4.     public RecyclerAdapter(Context context, List mDatas) {        
  5.         this.context = context;        
  6.         this.mDatas = mDatas;
  7.     }    
  8.     @Override
  9.     public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        
  10.         MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context)
  11.                 .inflate(R.layout.item_recycler_view, parent, false));        
  12.         return holder;
  13.     }    
  14.     @Override
  15.     public void onBindViewHolder(MyViewHolder holder, int position) {
  16.         holder.tv.setText(mDatas.get(position));
  17.     }    
  18.     @Override
  19.     public int getItemCount() {        
  20.         return mDatas == null ? 0 : mDatas.size();
  21.     }
  22.     public static class MyViewHolder extends RecyclerView.ViewHolder {        
  23.         TextView tv;
  24.         public MyViewHolder(View itemView) {            
  25.             super(itemView);
  26.             tv = (TextView) itemView.findViewById(R.id.tv);
  27.         }
  28.     }

3.3 RecyclerView.LayoutManager

LayoutManager的职责是摆放Item的位置,并且负责决定何时回收和重用Item。它有一个默认的实现:LinearLayoutManager,它可以用于垂直和水平列表。

RecyclerView.LayoutManager是一个抽象类,RecyclerView为我们提供3个实现类:

  1. LinearLayoutManager 现行管理器,支持横向、纵向。
  2. GridLayoutManager 网格布局管理器
  3. StaggeredGridLayoutManager 瀑布流式布局管理器

3.3.1 LinearlayoutManager

LinearlayoutManager是LayoutManager的默认实现。你可以使用这个类来创建垂直或水平列表。

 
 
 
 
  1. // 设置RecyclerView布局方式为纵向布局
  2. LinearLayoutManager layoutManager = new LinearLayoutManager(context);
  3. layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
  4. recyclerView.setLayoutManager(layoutManager); 
 
 
 
 
  1. // 设置RecyclerView布局方式为横向布局
  2. LinearLayoutManager layoutManager= new LinearLayoutManager(this);
  3. layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
  4. recyclerView.setLayoutManager(layoutManager);

运行程序,我们看到如下效果:

我们发现和ListView有一些不同,没有分割线让这个列表看起来很不美观,给RecyclerView设置分割线这个我们在下一小节说明。

当然LinearlayoutManager中还有一些很实用的API:

  • findFirstVisibleItemPosition() 返回当前***个可见Item的position
  • findFirstCompletelyVisibleItemPosition() 返回当前***个完全可见Item的position
  • findLastVisibleItemPosition() 返回当前***一个可见Item的position
  • findLastCompletelyVisibleItemPosition() 返回当前***一个完全可见Item的position

3.3.2 GridLayoutManager

有两个构造方法:

 
 
 
 
  1. /**
  2. * Creates a vertical GridLayoutManager
  3. *
  4. * @param context Current context, will be used to access resources.
  5. * @param spanCount 设置行数,因为默认是纵向的
  6. */public GridLayoutManager(Context context, int spanCount) {    
  7.     super(context);
  8.     setSpanCount(spanCount);
  9. }/**
  10. * @param context Current context, will be used to access resources.
  11. * @param spanCount 设置行数或者列数,根据方向
  12. * @param orientation 布局方向 HORIZONTAL or VERTICAL.
  13. * @param reverseLayout 是否反向显示 When set to true, layouts from end to start.
  14. */public GridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {    
  15.     super(context, orientation, reverseLayout);
  16.     setSpanCount(spanCount);

我们按如下代码设置:

 
 
 
 
  1. // 设置纵向的4列的表格布局GridLayoutManager layoutManager = new GridLayoutManager(this,4,GridLayoutManager.VERTICAL,false);
  2. recyclerView.setLayoutManager(layoutManager);
  3. // 设置横向的3行的表格布局GridLayoutManager layoutManager = new GridLayoutManager(this,3,GridLayoutManager.HORIZONTAL,false);
  4. recyclerView.setLayoutManager(layoutManager);  

3.3.3 StaggeredGridLayoutManager

我们来看StaggeredGridLayoutManager的构造方法,只有一个方法

 
 
 
 
  1. /**
  2. * Creates a StaggeredGridLayoutManager with given parameters.
  3. *
  4. * @param spanCount   设置行数或者列数,根据方向,纵向就是列数,横向就是行数
  5. * @param orientation 方向
  6. */ 
  7. public StaggeredGridLayoutManager(int spanCount, int orientation) {} 

因此我们这样设置:

 
 
 
 
  1. // 设置纵向的瀑布流布局
  2. StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL);
  3. recyclerView.setLayoutManager(layoutManager); 

我们看效果和GridLayoutManager没有什么区别呢,那我们来小小的修改一下,你就可以看到它的强大。

我们给每个item的布局加入margin:

 
 
 
 
  1.     android:orientation="vertical" android:layout_width="match_parent"
  2.     android:layout_height="wrap_content"
  3.     android:layout_margin="5dp"
  4.     android:background="@color/colorAccent">
  5.     
  6.         android:id="@+id/tv"
  7.         android:layout_width="100dp"
  8.         android:layout_height="100dp"
  9.         android:layout_gravity="center"
  10.         android:gravity="center"
  11.         android:textColor="#fff"
  12.         /> 

然后我们在适配器的onBindViewHolder方法中为我们的item设置个随机的高度:

 
 
 
 
  1. //贴上部分代码,其余的请看附件 
  2.     private List mHeights;    
  3.     public RecyclerAdapter(Context context, List mDatas) {        
  4.     this.context = context;        
  5.     this.mDatas = mDatas;
  6.         mHeights = new ArrayList();        
  7.             for (int i = 0; i < mDatas.size(); i++) {
  8.             mHeights.add((int) (100 + Math.random() * 300));
  9.         }
  10.     }
  11.     @Override    
  12.     public void onBindViewHolder(MyViewHolder holder, 
  13.         final int position) {
  14.         ViewGroup.LayoutParams lp = holder.tv.getLayoutParams();
  15.         lp.height = mHeights.get(position);
  16.         holder.tv.setLayoutParams(lp);
  17.     } 

运行,我们可以看到效果,是不是很炫!

3.4 RecyclerView.ItemDecoration

通过设置

 
 
 
 
  1. recyclerView.addItemDecoration(new DividerDecoration(Context context, int orientation));

来改变Item之间的偏移量或者对Item进行装饰。

例如,在上面的设置LinearlayoutManager之后加入以下代码,那么列表的效果就会发生改变:

  1. // 给纵向显示RecyclerView设置分割线
  2. recyclerView.addItemDecoration(new DividerItemDecoration(activity,DividerItemDecor

    网站名称:那年的RecyclerView我们从头撸一下
    网页地址:http://www.mswzjz.com/qtweb/news20/206620.html

    网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

    广告

    声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联