Android最新组件RecyclerView,替代ListView

RecyclerView简介

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

  • 定位项目布局管理器

  • 默认的动画为公用项的操作,例如删除或增加的项目

    您还可以在自定义的布局管理器和动画的灵活性RecyclerView部件。


    image.png

要使用RecyclerView小部件,你必须指定一个适配器和一个布局管理器。要创建一个适配器,扩展RecyclerView.Adapter类。实施的细节取决于你的数据集的具体情况和意见的类型。欲了解更多信息,请参见示例如下。
布局管理器 A的内部位置的项目意见RecyclerView,并确定何时再利用项目的看法不再对用户可见。重用(或回收)的图,布局管理器可能会问适配器与数据集不同的元素替换视图的内容。以这种方式回收的观点提高通过避免产生不必要的视图或执行昂贵性能findViewById()的查找。
RecyclerView提供这些内置的布局管理器:
LinearLayoutManager 显示在垂直或水平滚动列表项。
GridLayoutManager 显示在网格中的项目。
StaggeredGridLayoutManager 显示了交错网格项目。
要创建自定义布局管理器,扩展ecyclerView.LayoutManager类。
动画
动画的添加和删除项目中默认启用的RecyclerView。要自定义这些动画,延长 RecyclerView.ItemAnimator类,并使用RecyclerView.setItemAnimator() 方法。

RecyclerView的用法

下面简单介绍制作一个小Demo,来一步步分析一下RecyclerView的用法。首先说明一下,RecyclerView是ndroid.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的另外两个布局管理器就暂时不说了,大同小异。下面是运行效果图


image.png

为RecyclerView设置事件回调

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

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);
                }
            });
        }
    }
}

首先在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();
            }
        });

以下是运行效果图:


image.png

喜欢请点击+关注哦

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,695评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,569评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,130评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,648评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,655评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,268评论 1 309
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,835评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,740评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,286评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,375评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,505评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,873评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,357评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,466评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,921评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,515评论 2 359

推荐阅读更多精彩内容