Android 开发之漫漫长途 XV——RecyclerView

 关注 code小生 ,每日一篇技术推送!

作者:忘了12138
地址:http://www.cnblogs.com/wangle12138/p/8456508.html
声明:本文是 忘了12138 原创投稿,转发等请联系原作者授权。

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索》以及《深入理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相关知识,另外也借鉴了其他的优质博客,在此向各位大神表示感谢,膜拜!!!

前言

上文我们很详细的分析了ListView的使用、优化、及ListView的RecycleBin机制,读者如果对ListView不太清楚,那么请参看我的上篇博文。不过呢,Google Material Design提供的RecyclerView已经逐渐的取代ListView。RecyclerView提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果。

如果说上面的理由只是大而空泛的话,那我们来看以下场景

  1. 你想控制数据的显示方式,列表显示、网格显示、瀑布流显示等等,之前你需要ListView,GridView和自定义View,而现在你可以通过RecyclerView的布局管理器LayoutManager控制

  2. 你想要控制Item间的间隔(可绘制),想自定义更多样式的分割线,之前你可以设置divider,那么现在你可以使用RecyclerView的ItemDecoration,想怎么画怎么画。

  3. 你想要控制Item增删的动画,ListView呢我们只能自己通过属性动画来操作 Item 的视图。RecyclerView可使用ItemAnimator

  4. 你想要局部刷新某个Item,对于ListView来说,我们知道notifyDataSetChanged 来通知视图更新变化,但是该方法会重绘每个Item,而对于RecyclerView.Adapter 则提供了 notifyItemChanged 用于更新单个 Item View 的刷新,我们可以省去自己写局部更新的工作。

除了上述场景外,RecyclerView强制使用了ViewHolder模式,我们知道ListView使用ViewHolder来进行性能优化,但是这不是必须得,但是在RecyclerView中是必须的,另外RecyclerView还有许多优势,这里就不一一列举了,总体来说现在越来越多的项目使用RecyclerView,许多老旧项目也渐渐使用RecyclerView来替代ListView。

注:当我们想要一个列表显示控件的时候,需要支持动画,或者频繁更新,局部刷新,建议使用RecyclerView,更加强大完善,易扩展;其他情况下ListView在使用上反而更加方便,快捷。

前言我们就讲到这,那么我们来进入正题。

RecyclerView的使用

作为一个“新”控件,RecyclerView的使用有许多需要注意的地方

RecyclerView的简单使用

一样的我们新建一个Demo来演示RecyclerView的使用

[RecyclerViewDemo1Activity.java]

    public class RecyclerViewDemo1Activity extends AppCompatActivity {
       @BindView(R.id.recycler_view)
       RecyclerView mRecyclerView;

       private List<String> mData;

       @Override
       protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.activity_recycler_demo1_view);
           ButterKnife.bind(this);

           //LayoutManager必须指定,否则无法显示数据,这里指定为线性布局,
           mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
           //虚拟数据
           mData = createDataList();
           //设置Adapter必须指定,否则数据怎么显示
           mRecyclerView.setAdapter(new RecyclerViewDemo1Adapter(mData));
       }

       protected List<String> createDataList() {
           mData = new ArrayList<>();
           for (int i=0;i<20;i++){
               mData.add("这是第"+i+"个View");
           }
           return mData;
       }

   }

其对应的布局文件也很简单activity_recycler_demo1_view.xml

    <?xml version="1.0" encoding="utf-8"?>
   <LinearLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical"
       >


       <android.support.v7.widget.RecyclerView
           android:id="@+id/recycler_view"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           >

       </android.support.v7.widget.RecyclerView>


   </LinearLayout>

那么我们再来看RecyclerViewDemo1Adapter

    /**
    * 与ListView的Adapter不同,RecyclerView的Adapter需要继承RecyclerView.Adapter<VH>(VH是ViewHolder的类名)
    * 记为RecyclerViewDemo1Adapter。
    * 创建ViewHolder:在RecyclerViewDemo1Adapter中创建一个继承RecyclerView.ViewHolder的静态内部类,记为ViewHolder
    * (RecyclerView必须使用ViewHolder模式,这里的ViewHolder实现几乎与ListView优化时所使用的ViewHolder一致)
    * 在RecyclerViewDemo1Adapter中实现:
    *      ViewHolder onCreateViewHolder(ViewGroup parent, int viewType): 映射Item Layout Id,创建VH并返回。
    *      
    *      void onBindViewHolder(ViewHolder holder, int position): 为holder设置指定数据。
    *      
    *      int getItemCount(): 返回Item的个数。
    *      
    * 可以看出,RecyclerView将ListView中getView()的功能拆分成了onCreateViewHolder()和onBindViewHolder()。
    */

   public class RecyclerViewDemo1Adapter extends RecyclerView.Adapter<RecyclerViewDemo1Adapter.ViewHolder> {

       private List<String> mData;

       public RecyclerViewDemo1Adapter(List<String> data) {
           this.mData = data;
       }

       @Override
       public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
           View view = LayoutInflater
                       .from(parent.getContext())
                       .inflate(R.layout.item_menu_main, parent, false);

           return new ViewHolder(view);
       }

       @Override
       public void onBindViewHolder(ViewHolder holder, int position) {
           holder.setData(this.mData.get(position));
           holder.itemView.setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View v) {
                   //item点击事件
               }
           });
       }

       @Override
       public int getItemCount() {
           return this.mData != null ? this.mData.size() : 0;
       }

       static class ViewHolder extends RecyclerView.ViewHolder{
           private TextView mTextView;
           public ViewHolder(View itemView) {
               super(itemView);
               mTextView = (TextView) itemView.findViewById(R.id.tv_title);
           }

           public void setData(String title) {
               this.mTextView.setText(title);
           }
       }
   }

需要注意的是RecyclerView没有提供如ListView的setOnItemClickListener或者setOnItemLongClickListener之类的Item点击事件,我们必须自己去实现该部分功能,实现的方法有很多种,也比较容易,本例中采用在Adapter中BindViewHolder绑定数据的时候为item设置了点击事件。

小结

RecyclerView的四大组成分别是:

  • Adapter:为Item提供数据。必须提供,关于Adapter我们上面的代码注释已经说的很明白了

  • Layout Manager:Item的布局。必须提供,我们需要为RecyclerView指定一个布局管理器

  • Item Animator:添加、删除Item动画。可选提供,默认是DefaultItemAnimator

  • Item Decoration:Item之间的Divider。可选提供,默认是空

所以上面代码的运行结果看起来像是是一个没有分割线的ListView

640

RecyclerView的进阶使用

上面的基本使用我们是会了,而且点击Item也有反应了,不过巨丑无比啊有木有。起码的分割线都没有,真无语

为RecyclerView添加分割线

那么如何创建分割线呢,
创建一个类并继承RecyclerView.ItemDecoration,重写以下两个方法:

  • onDraw()或者onDrawOver: 绘制分割线。

  • getItemOffsets(): 设置分割线的宽、高。

然后使用RecyclerView通过addItemDecoration()方法添加item之间的分割线。

RecyclerView的缓存机制

RecyclerView和ListView的回收机制非常相似,但是ListView是以View作为单位进行回收,RecyclerView是以ViewHolder作为单位进行回收。相比于ListView,RecyclerView的回收机制更为完善

源码地址:源码传送门

此致,敬礼

640


猜你喜欢

转载自blog.csdn.net/H176Nhx7/article/details/79988344