RecyclerView详解

2019-09-12 11:34:33 浏览数 (1)

前言

Hello 艾维巴蒂,今天给大家介绍一下 ListViewGridView的“大哥“— RecyclerView,这个控件是当下最流行且最常用的一个控件,并且在实战项目中它随处可见,而为什么将它称为“大哥”,请听我们娓娓道来~

简介

RecyclerViewGoogle在API 21下 support.V7包里的控件,用来替代 ListViewGridView。官网对它的描述为:A flexible view for providing a limited window into a large data set。它是从Android5.0出现的全新列表组件,更加强大和灵活。

RecyclerViewsupport 包里默认提供了三个 LayoutManager,分别是下列三个,可用于实现大部分场景的布局需求:线性布局、网格布局、瀑布流布局等等。

1、 LinearLayoutManager 现行管理器,支持横向、纵向。

2、 GridLayoutManager 网格布局管理器

3、 StaggeredGridLayoutManager 瀑布流式布局管理器

基本用法

1.引入依赖

代码语言:javascript复制
implementation 'com.android.support:recyclerview-v7:27.1.1'

2.布局中添加RecyclerView

代码语言:javascript复制
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    tools:context=".recyclerview.RecyclerViewActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@ id/rv_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white" />
</LinearLayout>

如果想去掉可滑动控件滑动到边缘的光晕效果,小伙伴们可以这样试试:

代码语言:javascript复制
//在xml中设置
android:overScrollMode="never"
//在代码中设置
rvView.setOverScrollMode(View.OVER_SCROLL_NEVER);

3.Adapter适配器设置

在使用的时候更新需要使用 Adapter适配器。但是 RecyclerView使用的适配器并不是之前的 BaseAdapter了。RecyclerView使用的适配器需要继承 RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder>。这里 <>可能有些小白不知道是什么意思,大概说一下, <>这个是泛型,在箭括号里可以写自己定义好的适配器,因为而RecyclerView.ViewHolder本身是一个抽象类,我们往往自己继承这个抽象类,然后绑定我们的布局控件对象。继承该类时必须传入一个itemView,表示这个item显示的View,我这里自定义的适配器命名为MyViewHolder

Adapter中必须实现的三个方法:

a、//列表页需要知道有多少个条目publicintgetItemCount()

b、//创建一个ViewHolder,我们可以根据viewType的不同而创建不同的ViewHolder实现列表页各种不一样的itempublicRecyclerView.ViewHolderonCreateViewHolder(@NonNullViewGroupparent,intviewType)

c、//在ViewHolder中绑定数据publicvoidonBindViewHolder(@NonNullRecyclerView.ViewHolderholder,intposition)

这里我写了一个简单的聊天列表样式,并且对头像添加了点击事件

代码语言:javascript复制
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> {

    private Context mContext;
    private List<String> mList = new ArrayList<String>();
    private RecyclerViewAdapter.OnItemChatClickLitener mOnItemClickLitener;

    public RecyclerViewAdapter(Context context, RecyclerViewAdapter.OnItemChatClickLitener mLitener) {
        this.mContext = context;
        this.mOnItemClickLitener = mLitener;
    }

    public List<String> getData() {
        return mList;
    }

    @Override
    public RecyclerViewAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = View.inflate(mContext, R.layout.adapter_recyclerview_layout, null);
        return new RecyclerViewAdapter.MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final RecyclerViewAdapter.MyViewHolder holder, final int position) {
        final String str = mList.get(position);
        //判断String传值是否为空
        if (!TextUtils.isEmpty(str)) {
            //给姓名赋值
            holder.tvName.setText(str);
            //头像设置点击事件
            holder.ivHeadPortrait.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mOnItemClickLitener != null) {
                        mOnItemClickLitener.onItemClick(position);
                    }
                }
            });
        }
    }

    @Override
    public int getItemCount() {
        return mList.size();
    }

    public interface OnItemChatClickLitener {
        void onItemClick(int position);
    }

    /**
     * 新建一个适配器类,同时内部新建一个ViewHolder类并继承相相应的类
     */
    public class MyViewHolder extends RecyclerView.ViewHolder {

        TextView tvName;
        ImageView ivHeadPortrait;

        public MyViewHolder(View itemView) {
            // 这里很重要,参数中的View对象也很重要
            super(itemView);
            ivHeadPortrait = itemView.findViewById(R.id.iv_headportrait);
            tvName = itemView.findViewById(R.id.tv_name);
        }
    }
}

item的布局 R.layout.adapter_recyclerview_layout代码如下:

代码语言:javascript复制
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:paddingLeft="10dp"
    android:paddingRight="10dp">

    <ImageView
        android:id="@ id/iv_headportrait"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginTop="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="10dp"
        android:src="@mipmap/moren_icon" />

    <TextView
        android:id="@ id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="15dp"
        android:layout_toRightOf="@id/iv_headportrait"
        android:text="小红"
        android:textColor="@color/black"
        android:textSize="14sp"
        android:textStyle="bold" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@id/iv_headportrait"
        android:layout_toRightOf="@id/iv_headportrait"
        android:text="你领取了谁的红包"
        android:textColor="@color/color_9A9A9A"
        android:textSize="14sp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_marginTop="15dp"
        android:text="7分钟前"
        android:textColor="@color/color_9A9A9A"
        android:textSize="13sp" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:layout_below="@id/iv_headportrait"
        android:background="@color/color_9A9A9A" />
</RelativeLayout>

4.在activity中初始化RecyclerView,并配置具体用法已在代码中标注,如下:

代码语言:javascript复制
public class RecyclerViewActivity extends AppCompatActivity {

    private List<String> mList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recyclerview);
        RecyclerView rvView = (RecyclerView) findViewById(R.id.rv_view);
        RecyclerViewAdapter rvAdapter = new RecyclerViewAdapter(this, new RecyclerViewAdapter.OnItemChatClickLitener() {
            @Override
            public void onItemClick(int position) {
                //对头像添加了点击事件
                Toast.makeText(RecyclerViewActivity.this, "点击了:"   mList.get(position), Toast.LENGTH_SHORT).show();
            }
        });

        //LinearLayoutManager是用来做列表布局,也就是单列的列表
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        //设置为垂直布局,默认是垂直的(垂直:LinearLayoutManager.VERTICAL,水平:LinearLayoutManager.HORIZONTAL)
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        //设置布局管理器
        rvView.setLayoutManager(linearLayoutManager);
        //对RecyclerView设置Adapter
        rvView.setAdapter(rvAdapter);
        //给列表初始化数据
        setListData();
        rvAdapter.getData().addAll(mList);
        rvAdapter.notifyDataSetChanged();
    }

    /**
     * 给列表初始化数据
     */
    private void setListData() {
        mList = new ArrayList<String>();
        mList.add("小红");
        mList.add("imageview");
        mList.add("小蓝");
        mList.add("小绿");
        mList.add("小明");
        mList.add("TextView");
        mList.add("小花");
        mList.add("嘿嘿");
        mList.add("是你呀");
        mList.add("editview");
        mList.add("listview");
        mList.add("gridview");
        mList.add("ConstraintLayout");
        mList.add("Service");
        mList.add("Activity");
        mList.add("RelativeLayout");
        mList.add("嗯嗯");
        mList.add("小粉");
    }
}
代码语言:javascript复制
**步骤:**
    **1.获取RecyclerView对象 。**
    **2.初始化数据 。**
    **3.适配器实例化 。**
    **4.设置LayoutManager**
    **5.设置Adapter 。**
    注意敲黑板了:
    rvView.setLayoutManager(linearLayoutManager);
    要给recyclerview设置布局管理器,否则不显示内容

具体效果如下:

水平RecyclerView:

代码语言:javascript复制
//LinearLayoutManager是用来做列表布局,也就是单列的列表
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
//设置为垂直布局,默认是垂直的(垂直:LinearLayoutManager.VERTICAL,水平:LinearLayoutManager.HORIZONTAL)
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
//设置布局管理器
rvView.setLayoutManager(linearLayoutManager);

这里我们换一个布局样式:R.layout.adapter_rv_horizontal_layout

代码语言:javascript复制
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:paddingLeft="10dp"
    android:paddingRight="10dp">

    <ImageView
        android:id="@ id/iv_headportrait"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="10dp"
        android:src="@mipmap/moren_icon" />

    <TextView
        android:id="@ id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/iv_headportrait"
        android:layout_centerHorizontal="true"
        android:gravity="center_horizontal"
        android:text="小红"
        android:textColor="@color/black"
        android:textSize="14sp"
        android:textStyle="bold" />
</RelativeLayout>

具体效果如下:

上面我们已经初步体验了下 LinearLayoutManager,接下来看 GridLayoutManager

设置网格布局GridLayoutManager

日常开发经常需要有多行或多列的形式来展示各个卡位信息,而一些类似于九宫格之类的布局也可以用这个实现。只需要修改设置布局管理器即可,还是很nice的。

代码语言:javascript复制
//设置网格布局
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 4);
//设置布局管理器
rvView.setLayoutManager(gridLayoutManager);

效果如下:

*设置竖直瀑布流布局StaggeredGridLayoutManager *

这里同样还是修改设置布局管理器即可,秒秒钟的事情

代码语言:javascript复制
//设置竖直瀑布流布局
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL);
//设置布局管理器
rvView.setLayoutManager(staggeredGridLayoutManager);

效果如下:

瀑布流样式和网格样式的区别

也许有人会疑惑,瀑布流就是设置下几行或者几列,然后设定下方向而已。网格样式时不也一样是设置下几行或几列,也一样是要再设置个方向。那么为什么瀑布流不可以直接用网格样式来实现呢?它们两者有什么区别么?

有去尝试过的就清楚了,这是两种完全不一样的布局样式。下面以两者都设置为竖直方向多列的样式来区分:

1、网格样式每一行中的所有 item 高度是一致的,不同行可以不一样,但同行的都是一样的,因此它就实现不了瀑布流的样式了;瀑布流所有的 item 高度都允许不一样,所有能实现瀑布流样式。

2、网格样式支持 item 占据多列的宽度;瀑布流支持 item 占据总列数的宽度,不支持只占据其中几列。

3、当设置为水平方向样式时,以上结论中行列对调,宽度高度对调。

使用RecyclerView的优缺点

优点:

1、提供 ViewHolder模式,使得开发者真正操作的是 ViewHolder,而不是像 ListView中的 GridView,需要开发者自己 setTagview.getTag

2、同时支持列表布局和网格布局,而 ListView只能支持列表布局,网格布局需要用 GridView

3、支持瀑布流布局。我们不在需要为实现瀑布流效果而苦恼

4、操作动画。在对列表进行增加、删除时的动画。并且 Adapter提供了增加删除某个 item的方法

5、性能与拓展性。RecyclerView听起来像是回收的view,事实上, RecyclerView本身就不关心 View相关的显示、 View显示什么内容( ViewHolder来管理), View怎么摆放( LayoutManager来管理),也不关心动画( ItemAmator来管理),甚至连分割线它都不管(由 ItemDecoration来管理) 而它关心 View的回收复用,这跟性能有关系。所以名字用 Recycle也是有道理的。这样的好处是,把各个环节工作交付给了不同的类,类似“插件化”。特别方便拓展,自定义各种各样的差异化,而从这其中解耦出来

缺点:需要自己实现 OnItemClickListener点击事件(这么实用的需求,Google竟然让我们自己实现...,不过还好我们自己写)

结语

本篇完,如果你觉得本篇对你有所帮助,欢迎转载分享,标志出处即可,谢谢支持。

0 人点赞