【Android】RecyclerView

RecyclerView

RecyclerView简明

RecyclerView 在v7.21+包中,是一个用来展示大量数据的组件,或者说,就是ListView的改善版本(注:现阶段的功能没有ListView完善,因此想完全取代ListView的话并不明智)。
相比ListView,RecyclerView的扩展性更好,因此也更适合与android新曾的组件配合使用,这样使用起来更得心应手。

RecyclerView与ListView的原理差不多,本质上都是以适配器为核心。只不过ListView缓存的是view,viewHolder附着在view上,而RecyclerView缓存的是viewHolder,view包含在viewHolder内。

如果我们将ListViewAdapter稍作修改,也可以实现这种设计:

abstract class LvAdapter<VH extends LvAdapter.ViewHolder> extends BaseAdapter {

    public class ViewHolder {

        private View view;

        public ViewHolder(View view) {
            this.view = view;
        }

        public View getView() {
            return view;
        }
    }

    @Override
    public int getCount() {
        return 0;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        VH vh = getViewHolder();
        onBindViewHolder(vh, position);
        return vh.getView();
    }

    public abstract VH getViewHolder();

    public abstract void onBindViewHolder(VH holder, int position);
}

这样有点不直观,所以更进一步,ListView的Adapter可以更抽象,将数据绑定方法交给viewHolder,这样adapter的工作就更单纯一点.

一个方便的ListViewAdapter可以参考base-adapter-helper

RecyclerView使用

适配器

既然都是以适配器为核心,因此,只需要写好适配器就行了:

class RvViewHolder extends RecyclerView.ViewHolder {

    public TextView tv;

    public RvViewHolder(View itemView) {
        super(itemView);
        tv = (TextView) itemView.findViewById(R.id.tv);
    }
}

class RvAdapter extends RecyclerView.Adapter<RvViewHolder> {

    Context context;
    String[] items;

    public RvAdapter(Context context, String[] items) {
        this.context = context;
        this.items = items;
    }

    @Override
    public RvViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.apt_v7_recycler_view, parent, false);
        return new RvViewHolder(view);
    }

    @Override
    public void onBindViewHolder(RvViewHolder holder, int position) {
        holder.tv.setText(items[position]);
    }

    @Override
    public int getItemCount() {
        return items.length;
    }
}

rv.setAdapter(new RvAdapter(this, new String[]{
        "A", "B", "C", "D",
        "A", "B", "C", "D",
        "A", "B", "C", "D",
        "A", "B", "C", "D",
        "A", "B", "C", "D",
        "A", "B", "C", "D",
        "A", "B", "C", "D",
        "A", "B", "C", "D",
        "A", "B", "C", "D",
        "A", "B", "C", "D",
        "A", "B", "C", "D",
        "A", "B", "C", "D",
        "A", "B", "C", "D"
}));
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayout.VERTICAL);
rv.setLayoutManager(linearLayoutManager);

布局管理器 与 横向列表

RecyclerView的另一个特点就是布局管理器(LayoutManager),个人觉得的一个比较方便的地方就是,终于可以方便的实现横向列表了!布局管理的作用就是负责摆放view以及回收view。
类似的

int findFirstVisibleItemPosition();
int findLastVisibleItemPosition();

方法也在布局管理器中

设置item动画

rv.setItemAnimator(ItemAnimator);

分割线

由于RecyclerView的布局不固定,因此没有像ListView那样直接设定divider的方式,这些可能需要自己实现。一个简单粗鲁的纵向列表分割线如下:

rv.addItemDecoration(new RecyclerView.ItemDecoration() {

    Paint paint = new Paint();

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(c, parent, state);
        for (int i = 0, size = parent.getChildCount(); i < size; i++) {
            View child = parent.getChildAt(i);
            c.drawLine(child.getLeft(), child.getBottom(), child.getRight(), child.getBottom(), paint);
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
    }
});

还可以参考:DividerItemDecoration

绑定事件

RecyclerView 没有 ListView 的 OnItemClick 等方法,所以,类似方法需要自己处理。

  1. 可以直接给itemView或者其子view绑定事件,绑定可以在viewHolder中进行事件绑定,也可以在adapter中进行。
    不过viewHolder中无法直观获取到原始的Item数据,需要进一步的处理(比如给itemView设置tag)才能实现获取原始数据的目的,所以怎么使用需要自己权衡。

    class RvViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    public TextView tv;
    
    public RvViewHolder(View itemView) {
        super(itemView);
        tv = (TextView) itemView.findViewById(R.id.tv);
        itemView.setTag(this);
        itemView.setOnClickListener(this);
    }
    
    @Override
    public void onClick(View v) {
        int vId = v.getId();
        if (vId == R.id.tv) {
            Toast.makeText(itemView.getContext(), getPosition() + "", Toast.LENGTH_SHORT).show();
        }
    }

    }

  2. 可以使用
    addOnItemTouchListener(RecyclerView.OnItemTouchListener listener)

    来进行全局处理。当然,缺点就是需要处理事件细节,比较繁琐。

demo

demo

Android分享 Q群:315658668

时间: 2024-10-03 07:16:07

【Android】RecyclerView的相关文章

【Android】RecyclerView详解(一)

1.介绍 RecyclerView是比 ListView 更高级且更具灵活性的组件. 此组件是一个用于显示庞大数据集的容器,可通过保持有限数量的视图进行非常有效的滚动操作. 如果您有数据集合,其中的元素将因用户操作或网络事件而发生改变,请使用 RecyclerView 小组件. RecyclerView使用起来很方便因为它: 提供了一种插拔式的体验,高度的解耦,异常的灵活使用; 显示的样式更丰富包括水平,竖直,Grid,瀑布显示方式; 可以通过ItemDecoration自定义Item间的间隔;

【Android】Sqlite数据库增删改查

Android系统内置一个Sqlite数据库,如果app需要使用Sqlite数据库数据库存储数据,Android会为此app生成一个.db文件.这个数据库在data/data/<package_name>/databases里面,其中<package_name>为该安卓app的工程包名,这个目录必须root后才能看到.在Windows,单机的应用程序,存储数据,基本放到一个文件里面,正如游戏的存档,基本就是把当前的游戏状态存到一个用户很难找到的文件里面.每次存档读档就是一个从这个存

【Android】多个Activity之间利用bundle传递数值

安卓中的Activity相当于vb,mfc中的窗体,在多个Activity之间传递数据是一个相当核心的功能.下面举个例子来说明这个问题. 一.基本目标 用户在两个输入框中输入用户名.密码之后,跳到另一个Activity当中,显示其输入的内容, 然后这两个Activity能够轻松跳转. 二.制作过程 1.首先MainActivity的登录界面是沿用了<[Android]利用表格布局,Android中xml文件与java的交互制作登录界面>(点击打开链接)的布局,其布局文件activity_mai

【Android】自己定义View、画布Canvas与画笔Paint

安卓自己定义View事实上非常easy. 这个View能够像<[Android]利用Java代码布局,button加入点击事件>(点击打开链接)一样.利用Java代码生成一系列的组件. 也能够配合画布Canvas与画笔Paint来使用. 以下用一个样例来说明.例如以下图,有一个自己定义布局View.里面摆放着,利用画布Canvas与画笔Paint绘制出来的蓝色正方形与红色文字. 在res\layout\activity_main.xml中.直接像摆放安卓固有组件一样,能够直接使用这个我定义组件

【android】让popupwindow显示在view的上方并与该view水平居中对齐

首先,废话少说,先上效果图: 代码: public class MainActivity extends Activity implements OnClickListener{ private Button showBtn1; private Button showBtn2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentV

【Android】-- adb shell 命令探索

ADB是什么,做android开发的没有不知道的. window下运行cmd,输入adb help就会打印adb都能够做的事情,包括 adb push ..adb pull .. adb devices  adb install... 等等..并且一搜一大把. 其中有一个命令叫做  adb shell,android是基于linux的,shell模式下linux的命令可是非常多的,android去掉了许多linux的命令,那么从这写命令里面又能够发现什么宝藏呢?寻宝之旅开启!! 首先linux的

【Android】与服务器实现JSON数据通信

一.前言 作为一名移动端开发人员,具备一定的服务端开发能力也是非常必要的,本篇博客讲述如何在Android和服务器之间实现JSON数据通信交互,博客内容基于另外一篇博客:[Web]Eclipse + Maven + Struts搭建服务器. 二.服务器端改造 在博客[Web]Eclipse + Maven + Struts搭建服务器中,我们实现了服务器的搭建,现在要做的事情就是让它返回的数据是一个JSON格式的,这样在获得请求的时候,我们才可以得到JSON数据,其配置改变如下. 首先我们新建一个

【Android】Could not find XXX.apk!的解决方法

昨天在Eclipse中导入一个Android工程后点击运行时出现了Could not find XXX.apk!的错误信息,具体错误提示如下: 到网上搜了好多方法,挨个尝试,最后都没解决但是,重启Eclipse居然好了,    观察发现在bin目录下没有apk文件,可能是因为工程没有完全编译通过无法生成apk,所以project-->clean,然后rebuild就可以了~ 另外可以手动导出无签名的apk然后在导入到模拟器中,对于如何将apk导入到模拟器中可以参考这篇文章: http://wan

【Android】Android中Service类onStartCommand的返回值有关问题(转)

@Override public int onStartCommand(Intent intent, int flags, int startId) { System.out.println("---------->>onStartCommand2"); return super.onStartCommand(intent, flags, startId); } Android开发的过程中,每次调用startService(Intent)的时候,都会调用该Service对象