RecyclerView是什么?

RecyclerView是一种新的视图组,目标是为任何基于适配器的视图提供相似的渲染方式。它被作为ListView和GridView控件的继承者,在最新的support-V7版本中提供支持。

在开发RecyclerView时充分考虑了扩展性,因此用它可以创建想到的任何种类的的布局。但在使用上也稍微有些不便。这就是Android——要完成一件事情总不是那么容易。

如果使用RecyclerView,你需要了解以下三个元素:

  • RecyclerView.Adapter
  • LayoutManager
  • ItemAnimator

RecyclerView.Adapter

RecyclerView包含了一种新型适配器。它与现在使用的适配器类似,但也稍有不同,例如它需要使用ViewHolder。使用时需要重写两个主要方法:一个用来展现视图和它的持有者,而另一个用来把数据绑定到视图上。这么做的好处是,第一种方法只有当我们真正需要创建一个新视图时才被调用,不需要检查它是否已经被回收。

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
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.ViewHolder> {
 
    private List<ViewModel> items;
    private int itemLayout;
 
    public MyRecyclerAdapter(List<ViewModel> items, int itemLayout) {
        this.items = items;
        this.itemLayout = itemLayout;
    }
 
    @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(itemLayout, parent, false);
        return new ViewHolder(v);
    }
 
    @Override public void onBindViewHolder(ViewHolder holder, int position) {
        ViewModel item = items.get(position);
        holder.text.setText(item.getText());
        holder.image.setImageBitmap(null);
        Picasso.with(holder.image.getContext()).cancelRequest(holder.image);
        Picasso.with(holder.image.getContext()).load(item.getImage()).into(holder.image);
        holder.itemView.setTag(item);
    }
 
    @Override public int getItemCount() {
        return items.size();
    }
 
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ImageView image;
        public TextView text;
 
        public ViewHolder(View itemView) {
            super(itemView);
            image = (ImageView) itemView.findViewById(R.id.image);
            text = (TextView) itemView.findViewById(R.id.text);
        }
    }
}

这是一个简单的适配器,但是事情逐渐开始变得有点复杂。在RecyclerView中,没有一个onItemClickListener方法(至少我没有发现)。所以适配器是一个处理事件的良好的候选人。

如果想要从适配器上添加或移除条目,需要明确通知适配器。这与先前的notifyDataSetChanged()方法稍微有些不同。

1
2
3
4
5
6
7
8
9
10
public void add(ViewModel item, int position) {
    items.add(position, item);
    notifyItemInserted(position);
}
 
public void remove(ViewModel item) {
    int position = items.indexOf(item);
    items.remove(position);
    notifyItemRemoved(position);
}

LayoutManager

这个类决定视图被放在画面中哪个位置,但这只是它的众多职责之一。它可以管理滚动和循环利用。

LayoutManager只有一个叫做LinearLayoutManager的实现类,它有1500多行代码。但从这一点就可以看出它有多复杂。管理器可以模拟列表视图(包括横向和纵向),但没有页眉和页尾。

为LayoutManager编写子类不太适合新手,我们需要依靠社区来发掘RecyclerView的全部潜力。与这个例子一起,在短时间内我会上传一个GridView控件的实现。

我认为这背后的关键是要仿照LinearLayoutManager的代码创建一个BaseLayoutManager,并且基于此进行扩展。或许support-v7的最终版本会提供更多、更好的实现。

ItemAnimator

ItemAnimator会根据适配器上收到的通知动画显示视图组的修改。基本上,它会自动显示添加和移除条目动画。这也不是一个简单的类,但我们发现DefaultItemAnimator已经可以运行得很好了。

RecyclerView设置

所以最后,如果想要初始化一个运行的RecyclerView,你需要做这样的事情:

1
2
3
4
5
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.list);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(new MyRecyclerAdapter(createMockList(), R.layout.item));
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setItemAnimator(new DefaultItemAnimator());

setHasFixedSize()方法用来使RecyclerView保持固定的大小,该信息被用于自身的优化。

总结

RecyclerView确实是一个强大的视图,它为开发者提供了无限的扩展能力。学习曲线可能会非常陡峭。但我相信,不久Android社区就会发布LayoutManager超棒的实现。

我在创建一个github仓库,在那里可以找到这个例子。它是我计划创建的一个扩展库的基础。你可以测试GridView的实现。欢迎各种形式的反馈。

recycleview的更多相关文章

  1. RecycleView 实现多布局

    最近的一个新需求,简单描述下吧: 需求: 目标样式如图所示,我们需要根据需求动态添加网关和设备. 目标有了下面就是怎么实现了.首先我们选用的是RecycleView 那么主要目标就成了 在recycl ...

  2. ScrollView中嵌套recycleView 出现的不显示,显示不全,终极解决方案

    最近公司项目中用到了ScrollView去嵌套recycleView, 最开始我天真的把recycleView直接放入scrollView中,结果可想而知,什么都不显示,瞬间懵逼,我心想应该是和嵌套L ...

  3. RecycleView + CardView 控件简析

    今天使用了V7包加入的RecycleView 和 CardView,写篇简析. 先上效果图: 原理图: 这是RecycleView的工作原理: 1.LayoutManager用来处理RecycleVi ...

  4. RecycleView在eclipse的初体验

    在sdk中找到v7包 \sdk\extras\android\support\v7\recyclerview 导入工程 Import\Android\Existing Android Code Int ...

  5. android recycleview 中禁止多点触发

    int currentapiVersion = android.os.Build.VERSION.SDK_INT; if (currentapiVersion >= android.os.Bui ...

  6. android基础开发之RecycleView(1)---基本使用方式

    RecycleView是google为了优化listview,gridview 提供的一个新的控件. 1.android 导入recycleview 在app的gradle里面加入: dependen ...

  7. Android RecycleView + CardView 控件简析

    今天使用了V7包加入的RecycleView 和 CardView,写篇简析. 先上效果图: 原理图: 这是RecycleView的工作原理: 1.LayoutManager用来处理RecycleVi ...

  8. recycleview中使用checkbox导致的重复选中问题

    参考博文:http://www.myexception.cn/mobile/1852852.html 在使用RecycleView做仿微信图片选择器,其中条目中使用了checkbox,在选中时由于ho ...

  9. 自己封装的工具类,使用原生SwipeRefreshLayout+RecycleView实现下拉刷新和加载更多

    实现SwipeRefreshLayout+RecycleView实现刷新 在你的xml文件里写上如下代码: <android.support.v4.widget.SwipeRefreshLayo ...

  10. android5.0中RecycleView的用法

    最近学习了android5.0中新增的一个组件RecycleView,是用来代替当前的listview开发的,是因为在RecycleView中已经有了viewholder缓存,并且不同的item之间可 ...

随机推荐

  1. 仿Iconfont-阿里巴巴矢量图标库 搜索动画

    效果图如下 style <Style x:Key="BtnSearch" TargetType="{x:Type Button}"> <Set ...

  2. CSS倒影

    前面的话   CSS倒影目前只有chrome和safari浏览器支持,且需要添加-webkit-前缀.本文将详细介绍CSS倒影box-reflect 语法 -webkit-box-reflect 初始 ...

  3. BZOJ1013 [JSOI2008]球形空间产生器sphere(高斯消元)

    1013: [JSOI2008]球形空间产生器sphere Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4846  Solved: 2525[Subm ...

  4. Asio C++ Library,libuv - Cross-platform asynchronous I/O

    http://think-async.com/ http://libuv.org/ https://github.com/libuv/libuv

  5. PHP多维数组元素操作类

    我的框架里面一个多维数组元素操作类,主要用于读取数组中配置数据,可以通过字符串节点的方式:a.b.c 来获取和设置元素,以及多维数组的覆盖,有需求的可以参考下吧! <?php /** * Cre ...

  6. D3.js:坐标轴

    坐标轴: 是可视化图表中经常出现的一种图形,由一些列线段和刻度组成.坐标轴在 SVG 中是没有现成的图形元素的,需要用其他的元素组合构成.D3 提供了坐标轴的组件,如此在 SVG 画布中绘制坐标轴变得 ...

  7. jmeter(八)-JDBC请求(sqlserver)

    做JDBC请求,首先要了解这个JDBC对象是什么,然后寻找响应的数据库连接URL和数据库驱动. 数据库URL:jdbc:sqlserver://200.99.197.190:1433;database ...

  8. java基础:int和integer区别

    int是基础数据类型: integer是包装类,里面包含一些基础的方法,最常见的就是数据转换: 比如int转String: int a=0: String b=Integer.toString(a):

  9. 导入excel成一个list集合不支持大文件倒入(优化点在于分批分线程导入)

    package com.bj58.saletb.news.utils; import org.apache.log4j.Logger; import org.apache.poi.ss.usermod ...

  10. PAT乙级1001. 害死人不偿命的(3n+1)猜想 (15)

    卡拉兹(Callatz)猜想: 对任何一个自然数n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把(3n+1)砍掉一半.这样一直反复砍下去,最后一定在某一步得到n=1.卡拉兹在1950年的世界数 ...