这都8102了,还不使用RecyclerView来创建列表吗

官方文档地址:https://developer.android.com/guide/topics/ui/layout/recyclerview#top_of_page

如果你的应用需要显示基于大型数据集(或经常需要更改的数据)的滚动元素列表,你应该使用RecyclerView来完成这项工作

左图是一个使用了RecyclerView的列表,右图则是在RecyclerView还用上了CardView

RecyclerView概述

RecyclerView是一个比ListView更高级也更加灵活的控件。

RecyclerView这个模型是由几个不同的组件协同工作以显示数据的,呈现出的包含用户界面的容器就是一个RecyclerView对象,这个对象是开发者添加到xml布局文件中的。填充RecyclerView的视图来自开发者提供的布局管理器(LayoutManager),开发者可以使用谷歌提供的标准布局管理器,如LinearLayoutManager或GridLayoutManager,当然也可以使用自定义的LayoutManager。

列表中的每个item视图就是一个ViewHolder,这些ViewHolder对象是开发者通过继承RecyclerView.ViewHolder定义的类的实例。每一个ViewHolder都负责显示item视图,例如,如果你的列表需要显示音乐集,则每个ViewHolder就可能代表一个专辑。RecyclerView创建的仅仅是那些显示出来的动态内容所需的ViewHolder,它们都在手机屏幕内,除此之外还有一些额外的视图。当用户滚动列表时,RecyclerView会获取屏幕外的视图并将它们重新绑定到屏幕上正在滚动的数据中。

ViewHolder对象由适配器(Adapter)管理,开发者可以通过继承RecyclerView.Adapter来创建适配器,并在Adapter中根据需要来创建ViewHolder。Adapter会将ViewHolder绑定到它的数据中,具体就是Adapter将ViewHolder分配到列表中的一个位置上,这个操作是调用Adapter的onBindViewHolder()方法来完成的,这个方法通过ViewHolder在列表中的位置来确定显示的具体内容是什么。

RecyclerView本身做了很多优化工作,如下:

  • 首次填充列表时,它会在列表中创建并绑定一些ViewHolder。举个例子,如果列表显示的视图位置是从0~9,则RecyclerView会创建并绑定这些ViewHolder,它可能也会创建并绑定处在位置10的ViewHolder。如此一来,当用户要开始滚动列表时,下一个元素已经准备好了。
  • 当用户滚动列表时,RecyclerView会根据需要来创建新的ViewHolder,它还可以保存已经滚动到屏幕外的ViewHolder,因此这些ViewHolder是可以重复利用的。如果用户切换了列表的滚动方向,则滚动到屏幕外的那些ViewHolder是可以回到屏幕内的。另一方面,如果用户继续以当前的方向滚动列表,则可以将已经不在屏幕内的那些ViewHolder重新绑定到新的数据中。ViewHolder是不需要被创建或填充视图的,取而代之的是,应用程序只需要更新ViewHolder的内容,从而匹配它所绑定的新item即可。
  • 当显示的item发生变化时,开发者可以通过调用适当的RecyclerView.Adapter.notify ...()方法来通知Adapter。然后Adapter会重新绑定发生了变化的item。

添加支持库

要想使用RecyclerView,需要将v7支持库添加到项目中,如下所示:

  1. 打开app module的build.gradle文件
  2. 将支持库添加到dependencies部分。
dependencies {
    implementation 'com.android.support:recyclerview-v7:28.0.0'
}

添加RecyclerView到布局文件中

现在,你可以将RecyclerView添加到布局文件中。例如,以下布局使用RecyclerView作为整个布局的唯一视图:

<?xml version="1.0" encoding="utf-8"?>
<!-- A RecyclerView with some commonly used attributes -->
<android.support.v7.widget.RecyclerView
    android:id="@+id/my_recycler_view"
    android:scrollbars="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

将RecyclerView添加到布局之后,接下来就是获取这个RecyclerView对象,将其连接到布局管理器,并为其指定Adapter:

public class MyActivity extends Activity {
    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_activity);
        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

        //如果你确定内容的变化不会更改RecyclerView的布局大小,可以使用这个设置来提高性能
        mRecyclerView.setHasFixedSize(true);

        //使用线性布局管理器
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        // 指定适配器
        mAdapter = new MyAdapter(myDataset);
        mRecyclerView.setAdapter(mAdapter);
    }
    // ...
}

新建一个Adapter

为了将所有数据都添加给列表,开发者必须新建一个继承了RecyclerView.Adapter的类,这个类负责帮助item创建视图,并在需要时更新item中的视图和数据。

以下代码示例显示了一个Adapter的简单实现:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    private String[] mDataset;

    // 提供对每个数据项的视图的引用,较为复杂的item可能会包含多个视图,你可以访问ViewHolder中的所有view
    public static class MyViewHolder extends RecyclerView.ViewHolder {
        // each data item is just a string in this case
        public TextView mTextView;
        public MyViewHolder(TextView v) {
            super(v);
            mTextView = v;
        }
    }

    // 提供合适的构造函数(这取决于数据集的类型)
    public MyAdapter(String[] myDataset) {
        mDataset = myDataset;
    }

    // 创建新的视图(由布局管理器调用)
    @Override
    public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
                                                   int viewType) {
        // 创建一个新视图
        TextView v = (TextView) LayoutInflater.from(parent.getContext())
                .inflate(R.layout.my_text_view, parent, false);
        ...
        MyViewHolder vh = new MyViewHolder(v);
        return vh;
    }

    // 替换视图的内容(由布局管理器调用)
    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        //更新视图ui
        holder.mTextView.setText(mDataset[position]);

    }

    // 返回数据集的大小(由布局管理器调用)
    @Override
    public int getItemCount() {
        return mDataset.length;
    }
}

布局管理器(LayoutManager)会调用Adapter的onCreateViewHolder()方法,这个方法会创建一个RecyclerView.ViewHolder,并设置其用于显示内容的视图。ViewHolder的类型必须与Adapter类签名中声明的类型匹配,ViewHolder通过填充xml布局文件来设置视图。如上代码中,因为还没由分配数据给ViewHolder,因此onCreateViewHolder()实际上还未设置视图的内容。

在创建完一个ViewHolder之后,LayoutManager会将数据到ViewHolder中,这个过程是通过LayoutManager调用Adapter的onBindViewHolder()方法来实现的,与此同时还会将ViewHolder的位置信息传递给RecyclerView。onBindViewHolder()方法需要获取数据来填充ViewHolder的布局。举个例子,如果RecyclerView正在显示一个name列表,则该方法可能会在列表中找到name,并设置给ViewHolder中的TextView。

如果列表需要更新,可以调用Adapter对象的相关通知方法,如notifyItemChanged(),如此一来,LayoutManager会重新绑定需要更新的ViewHolder,从而允许它数据被更新。

自定义你的RecyclerView

虽然标准类已经提供了大多数开发人员所需的所有功能,但你仍然可以自定义一个RecyclerView满足特定需求。在很多时候,你需要做的自定义其实就是为不同的ViewHolder设计不同的视图,并且使用数据去更新这些视图。但如果你的应用程序有其他的特定要求,你还是可以通过多种方式来修改原有的一些标准,如下描述了一些常见的自定义方式:

修改布局

RecyclerView使用LayoutManager在屏幕上定位各个item,并确定那些对于用户不可见的item视图何时重用。如果要重用(或回收)视图的话,LayoutManager可能会要求Adapter使用与新的数据来替换视图中内容,通过这种方式来回收view可以避免创建不必要的视图或执行代价较大的findViewById(),从而提高了性能。Android支持库中有三个标准的LayoutManager,每个LayoutManager都提供了许多自定义选项:

  • LinearLayoutManager将item以线性样式排列,使用带有LinearLayoutManager的RecyclerView提供的功能类似于以前的ListView布局。
  • GridLayoutManager将item以网格样式排列,就像棋盘上的一个个方块一样。使用带有GridLayoutManager的RecyclerView提供的功能类似于以前的GridView布局。
  • StaggeredGridLayoutManager也是将item以网格样式排列,但每个item的长或宽并不固定。

添加item动画

每当item发生变化时,RecyclerView都会使用animator,也就是动画来配合这个变化的过程。这个animator是一个抽象类的对象,它继承了RecyclerView.ItemAnimator类。在默认情况下,RecyclerView使用DefaultItemAnimator来提供动画,如果开发者想自己来提供自定义的动画,可以通过继承RecyclerView.ItemAnimator类来完成。

启用列表item选中

通过使用recyclerview-selection库,开发者可以使用触摸或鼠标输入在RecyclerView列表中选中item。你可以控制所选item的可视化表示,还可以持有选中后行为的控制,例如哪些item可以选中,以及可以选择的item有多少个。

要向RecyclerView实例添加选中支持,请按照下列步骤操作:

  1. 确定要使用的选择键类型,然后构建ItemKeyProvider。你可以使用三种选择键类型来标识所选的item:Parcelable(以及所有子类,如Uri),String和Long。有关选择键类型的详细信息,请到文档中查看SelectionTracker.Builder。
  2. 实现ItemDetailsLookup接口,ItemDetailsLookup能够使选择库在给定MotionEvent的情况下访问有关RecyclerView中item的信息。
  3. 在RecyclerView中更新item的视图,从而体现出用户是选择还是取消选择。selection库并不会为所选item提供默认的ui效果,所以你必须在onBindViewHolder()时设置视图的具体内容。建议的方法如下:

    (1)在onBindViewHolder()中,根据是否选择了该item来调用View的setActivated()方法(不是setSelected())。

    (2)为了表示出激活状态,需要更新视图样式,建议使用颜色状态列表资源来配置样式。

  4. 使用ActionMode为用户提供 选择执行 这个操作的工具。注册SelectionTracker.SelectionObserver,以便在选择更改时收到通 

    知。首次创建选择时,启动ActionMode将其表示给用户,并提供相应的操作。例如,你可以向ActionMode栏添加删除按钮,同时ActionMode栏上的后退箭头用来清除选择,如果用户最后一次清除了选择,不要忘记终止。

  5. 在事件处理结束时执行辅助操作,通过点击它来确定用户是否正在激活item或者正在拖拽Item等。通过注册适当的监听器来做出反应。更多详细信息,请到文档中SelectionTracker.Builder。

  6. 使用SelectionTracker.Builder来组合所有内容。下面的示例代码显示了如何使用Long选择键将这些片段放在一起:

SelectionTracker tracker = new SelectionTracker.Builder<>(
        "my-selection-id",
        recyclerView,
        new StableIdKeyProvider(recyclerView),
        new MyDetailsLookup(recyclerView),
        StorageStrategy.createLongStorage())
        .withOnItemActivatedListener(myItemActivatedListener)
        .build();

为了构建SelectionTracker实例,你的应用程序必须提供用于将RecyclerView初始化为SelectionTracker.Builder的相同RecyclerView.Adapter。因此,在创建RecyclerView.Adapter之后,你很可能需要在创建后将SelectionTracker实例注入RecyclerView.Adapter。否则你将无法在onBindViewHolder()方法中查看item的选定状态。

7. 在Activity生命周期事件中包括选择。为了保持Activity生命周期事件中的选中状态,必须分别在Activity的                                        onSaveInstanceState()和onRestoreInstanceState()方法中调用选择跟踪器的onSaveInstanceState()和                                          onRestoreInstanceState()方法。除此之外,还必须为SelectionTracker.Builder构造函数提供唯一的选择ID。这个ID是必需            的,因为Activity或Fragment可能具有多个不同的可选列表,所有这些列表都需要以其保存状态保留。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值