Android最新组件RecyclerView,替代ListView

Android最新组件RecyclerView,替代ListView

时间 2014-10-22 20:08:48 CSDN博客html

原文  http://blog.csdn.net/allen315410/article/details/40379159java

主题 RecyclerView ListViewandroid

转载请注明出处: http://blog.csdn.net/allen315410/article/details/40379159ios

万众瞩目的android最新5.0版本不久前已经正式发布了,对于我这样对新事物不感冒的人来讲,天然也是会关注的,除了新的android5.0带来的新的UI设计和用户体验以外,最让android程序员感兴趣的是5.0版本的sdk和一大堆新的API。5.0听说是额外增长或者修改了5000个API,新增了一些新的组件,下面介绍的RecyclerView就是其中之一,有人说Google设计出的RecyclerView是为了替代一直经常使用的ListView的,因此既然如此,咱们就没理由不看看这个“传说”中的RecyclerView是怎么使用的了。程序员

RecyclerView简介

该RecyclerView widget是一种更先进的柔性版的ListView。这个小工具是一个容器,用于显示,能很是有效地维护了意见数量有限,滚动大的数据集。使用 RecyclerView当你拥有的数据的集合,它的元素在运行时改变基于用户行为和网络事件的小部件。缓存

该RecyclerView类简化,提供显示和处理大数据集:网络

定位项目布局管理器app

默认的动画为公用项的操做,例如删除或增长的项目ide

您还能够在自定义的布局管理器和动画的灵活性RecyclerView部件。函数

要使用RecyclerView小部件,你必须指定一个适配器和一个布局管理器。要建立一个适配器,扩展RecyclerView.Adapter类。实施的细节取决于你的数据集的具体状况和意见的类型。欲了解更多信息,请参见示例以下。

布局管理器 A的内部位置的项目意见RecyclerView,并肯定什么时候再利用项目的见解再也不对用户可见。重用(或回收)的图,布局管理器可能会问适配器与数据集不一样的元素替换视图的内容。以这种方式回收的观点提升经过避免产生没必要要的视图或执行昂贵性能findViewById()的查找。

RecyclerView提供这些内置的布局管理器:

LinearLayoutManager 显示在垂直或水平滚动列表项。

GridLayoutManager 显示在网格中的项目。

StaggeredGridLayoutManager 显示了交错网格项目。

要建立自定义布局管理器,扩展RecyclerView.LayoutManager类。

动画

动画的添加和删除项目中默认启用的RecyclerView。要自定义这些动画,延长 RecyclerView.ItemAnimator类,并使用RecyclerView.setItemAnimator() 方法。

以上内容来自 Google官方文档 的翻译,翻译比较生涩(我这英文水平,哎~~对付本身还行),下面直接上一个Demo看看具体的用法。

RecyclerView的用法

下面简单介绍制做一个小Demo,来一步步分析一下RecyclerView的用法。首先说明一下,RecyclerView是android.support.v7包下提供的组件,因此须要使用RecyclerView时,须要下载这个包,因为我已经将SDK升级到最新版本——API21,因此很容易在/sdk/extras/android/support/v7/appcompat/libs目录下找到这个jar以及源码,建议先升级sdk,再动手作!实在不想动手的下载的,点击博文下方的连接下载源码,源码里有RecyclerView的JAR包。

主界面布局,activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:layout_centerVertical="true"
        android:background="@android:color/transparent"
        android:scrollbars="none" />

</RelativeLayout>

Item布局,item_recyclerview.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="120dp"
    android:layout_height="120dp" >

    <ImageView
        android:id="@+id/iv_image"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:scaleType="centerCrop" />

</RelativeLayout>

RecyclerView的数据适配器,MyAdapter.java

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

    private int[] mDataset; // 外面传入的数据

    public static class ViewHolder extends RecyclerView.ViewHolder {

        ImageView mImageView;

        // TODO Auto-generated method stub
        public ViewHolder(View v) {
            super(v);
        }

    }

    public MyAdapter(int[] mDataset) {
        this.mDataset = mDataset;
    }

    /**
     * 获取总的条目数量
     */
    @Override
    public int getItemCount() {
        // TODO Auto-generated method stub
        return mDataset.length;
    }

    /**
     * 建立ViewHolder
     */
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // TODO Auto-generated method stub
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycleview, parent, false);
        ViewHolder holder = new ViewHolder(v);
        holder.mImageView = (ImageView) v.findViewById(R.id.iv_image);
        return holder;
    }

    /**
     * 将数据绑定到ViewHolder上
     */
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // TODO Auto-generated method stub
        holder.mImageView.setImageResource(mDataset[position]);
    }
}

从上面能够看出这个数据适配器跟ListView用的BaseAdapter上比,已经发生了很大的变化。首先数据适配器须要继承RecyclerView.Adapter<VH>类,该类是个泛型类,泛型类型也是ViewHolder,这个ViewHolder毋庸置疑就是实现组件复用的,Google已经帮咱们定义好了,在RecyclerView里是个内部类,可是具体实现仍是扔给android App开发者去实现,须要在适配器类创建一个内部类,而且继承RecyclerView,ViewHolder,在这个内部类里面定义出Item布局上全部须要复用的组件,最后将这个内部类做为泛型传递给RecyclerView.Adapter<VH>,实现须要复写的3个方法:

getItemCount() 获取Item的总数。

onCreateViewHolder(ViewGroup parent, int viewType) 建立ViewHolder。

onBindViewHolder(ViewHolder holder, int position) 将数据绑定到ViewHolder。

与ListView数据适配的对比

ListView里面有个getView()方法返回的View是Item的布局,那么这个RecyclerView的Item的布局在哪控制?实际上是这样的,RecyclerView对ViewHolder也进行了必定的封装,咱们建立的ViewHolder必须继承RecyclerView.ViewHolder,这个RecyclerView.ViewHolder的构造时必须传入一个View,这个View至关于咱们ListView的getView()中的convertView (即:咱们须要inflate的item布局须要传入)。

还有一点,ListView中convertView是复用的,在RecyclerView中,是把ViewHolder做为缓存的单位了,而后convertView做为ViewHolder的成员变量保持在ViewHolder中,也就是说,假设没有屏幕显示10个条目,则会建立10个ViewHolder缓存起来,每次复用的是ViewHolder,因此他把getView这个方法变为了onCreateViewHolder。

最后,就在Activity里使用这个RecyclerView,MainActivity.java

public class MainActivity extends Activity {

    /** RecyclerView对象 */
    private RecyclerView recyclerView;
    /** 图片资源 */
    private int[] mDataset;
    /** 数据适配器 */
    private MyAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
        // 初始化图片数据
        mDataset = new int[] { R.drawable.a, R.drawable.b, //
                R.drawable.c, R.drawable.d, R.drawable.e, //
                R.drawable.f, R.drawable.g, R.drawable.h, R.drawable.i };
        // 设置布局管理器
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
        recyclerView.setLayoutManager(linearLayoutManager);
        // 设置适配器
        mAdapter = new MyAdapter(mDataset);
        recyclerView.setAdapter(mAdapter);
    }
}

在MainActivity使用RecyclerView如同使用ListView同样的简单,惟一不一样的地方就是,须要给RecyclerView设置一个布局管理器,Google为咱们提供了3种不一样的布局管理(详细请看最上面的简介),这里我使用的LinearLayoutmanager,而且设置布局为水平显示。 好了,关于RecyclerView的基本用法讲完了,那个关于RecyclerView的另外两个布局管理器就暂时不说了,大同小异。下面是运行效果图

为RecyclerView设置事件回调

再使用RecyclerView组件时,发现了一个使人“痛心疾首”的问题:RecyclerView竟然没有点击Item的事件监听设置,相似于ListView中起码有个setOnItemClickListener方法,用于监听Item点击并做出相应的逻辑处理。可是翻遍了RecyclerView的API,都没有发现这个或者相似这个功能的方法可用,这不得不说是个“悲剧”,还据说这个是为了替代ListView的,看来并非这样的,请Google出来解释解释啊!

好了,Google应该近期是不会解释的了,可是咱们得本身想办法解决这个问题,就是为RecyclerView添加一个回调函数,这个倒不难吧!实在没法领会的,能够看看我前面的那篇博文, Android自定义组件——仿ios滑动按钮 ,里面有一些相关的用法。下面是我在Adapter里添加的回调函数。

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

    private int[] mDataset; // 外面传入的数据

    /**
     * Item的回调接口
     * 
     */
    public interface OnItemClickListener {
        void onItemClickListener(View view, int position);
    }

    private OnItemClickListener listener; // 点击Item的回调对象

    /**
     * 设置回调监听
     * 
     * @param listener
     */
    public void setOnItemClickListener(OnItemClickListener listener) {
        this.listener = listener;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {

        ImageView mImageView;

        // TODO Auto-generated method stub
        public ViewHolder(View v) {
            super(v);
        }

    }

    public MyAdapter(int[] mDataset) {
        this.mDataset = mDataset;
    }

    /**
     * 获取总的条目数量
     */
    @Override
    public int getItemCount() {
        // TODO Auto-generated method stub
        return mDataset.length;
    }

    /**
     * 建立ViewHolder
     */
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // TODO Auto-generated method stub
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycleview, parent, false);
        ViewHolder holder = new ViewHolder(v);
        holder.mImageView = (ImageView) v.findViewById(R.id.iv_image);
        return holder;
    }

    /**
     * 将数据绑定到ViewHolder上
     */
    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        // TODO Auto-generated method stub
        holder.mImageView.setImageResource(mDataset[position]);
        if (listener != null) {
            holder.mImageView.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    listener.onItemClickListener(v, position);
                }
            });
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

首先在Adapter里定义一个内部接口,接口内定义回调函数,而后向外暴露一个设置这个接口对象的方法,经过这个方法设置内部接口的对象,最后在ViewHolder绑定数据的方法中,经过接口对象调用接口方法,将相关信息传递出去。下面是在MainActivity里设置这个监听方法:

mAdapter.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClickListener(View view, int position) {
                // TODO Auto-generated method stub
                Toast.makeText(MainActivity.this, position + "", Toast.LENGTH_SHORT).show();
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如下是运行效果图:

源码请在这里下载

</div>
    <div class="article_social">
     <div class="article_like">
<div class="circle circle-like" id="my_zan" data_id="3IziIba">  </div>
  • 1
  • 2
  • 3
  • 4
相关文章
相关标签/搜索