概念

什么是recyclerView?我们常见的可以滑动的,分块的视图样式就可以认为是recyclerView。

比如:

recyclerview GridLayoutManager 设置item间距_android

在开发前还需要了解一些概念:

ViewHolder:可以看到recyclerView是以分块的视图形式组织的。分块无论其形状,里面的内容如何,每一个分快称之为ViewHolder。上图中一个title+subtitle的条形分块就是一个ViewHolder。

Adapter:可以确认的是,recyclerView一定是有数据填充的,也一定有一个工具性质的东西能够将数据正确地和每一个ViewHolder绑定,进而渲染其内容。实现这个流程的工具就是Adapter。

知道以上概念之后就可以开发了。

1.创建recylerView视图与对象

首先在需要展示的view里创建一个recyclerView:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

recyclerview GridLayoutManager 设置item间距_xml_02

随后在代码中获取其对象: 

mRecyclerView = this.findViewById(R.id.recycler_view);

此外,viewHolder的视图也需要自定义

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/list_item">

    <TextView
        android:id="@+id/main_title"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:textSize="30sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_centerVertical="true"
        tools:text="你好"/>

    <TextView
        android:id="@+id/subtitle"
        app:layout_constraintLeft_toLeftOf="@id/main_title"
        app:layout_constraintTop_toBottomOf="@id/main_title"
        android:layout_marginTop="10dp"
        android:textSize="12sp"
        android:layout_height="20dp"
        android:layout_width="wrap_content"
        android:layout_centerVertical="true"
        tools:text="是的"/>


</androidx.constraintlayout.widget.ConstraintLayout>

 

recyclerview GridLayoutManager 设置item间距_数据_03

2.创建数据类型

为了方便组织代码,我们通常将每个viewHolder中需要用到的数据抽象成一个data object。

public class ItemDTO {
    public String Title;
    public String subTitle;
}

这里为了方便,本地mock出一组给recylerView使用的数据(数组)。

private void mockData() {
        itemDTOList = new ArrayList<>();
        for (int i = 0; i < 20 ;i++) {
            ItemDTO itemDTO = new ItemDTO();
            itemDTO.Title = "title" + i;
            itemDTO.subTitle = "subtitle" + i;
            itemDTOList.add(itemDTO);
        }
    }

3.创建adapter和viewHolder

这是最难的一步,先贴上代码。

package recyclerview;

import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.recyclerview.widget.RecyclerView;

import com.example.myapplication.R;

import java.util.List;

public class ListViewAdapter extends RecyclerView.Adapter<ListViewAdapter.viewHolder> {
    private final static String TAG = "ListViewAdapter";
    // 绑定在recyclerView的数据集
    private final List<ItemDTO> mItemDTOList;

    public ListViewAdapter(List<ItemDTO> mItemDTOList) {
        this.mItemDTOList = mItemDTOList;
    }

    /**
     * 首次创建viewHolder时调用
     * @param parent
     * @param viewType
     * @return
     */
    @Override
    public viewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Log.d(TAG, "onCreateViewHolder");
        // 创建viewHolder
        View viewHolder = View.inflate(parent.getContext(), R.layout.list_view_item, null);
        return new ListViewAdapter.viewHolder(viewHolder);
    }

    /**
     * 上下滑动recyclerView调用
     * @param holder
     * @param position
     */
    @Override
    public void onBindViewHolder(ListViewAdapter.viewHolder holder, int position) {
        // 给对应位置的viewHolder绑定数据
        holder.bindData(mItemDTOList.get(position));
    }


    @Override
    public int getItemCount() {
        if (mItemDTOList == null || mItemDTOList.isEmpty()) {
            return 0;
        } else {
            return mItemDTOList.size();
        }
    }

    /**
     * viewHolder对象
     */
    public class viewHolder extends RecyclerView.ViewHolder {
        private final TextView mMainTitle;
        private final TextView mSubtitle;

        public viewHolder(View itemView) {
            super(itemView);
            mMainTitle = itemView.findViewById(R.id.main_title);
            mSubtitle = itemView.findViewById(R.id.subtitle);
        }

        /**
         * 将数据映射到每个viewHolder的视图上
         * @param itemDTO
         */
        public void bindData(ItemDTO itemDTO) {
            mMainTitle.setText(itemDTO.Title);
            mSubtitle.setText(itemDTO.subTitle);
            Log.d(TAG, "bindData: title = " + itemDTO.Title + " , subtitle = " + itemDTO.subTitle);
        }
    }
}

viewHolder

自定义的viewHolder集成了安卓原生的viewHolder,并自己实现了一个核心方法。

viewHolder有两个任务:

1.初始化viewHolder的视图组件

2.提供数据绑定的方法,将之前定义的data object里的数据设置到视图中。

核心方法:bindData,将data object里的数据设置到视图组件中。

Adapter

自定义的adapter继承了安卓原生的adapter,并重写两个核心方法。

adapter有三个任务:

1.获取到需要绑定到整个recyclerView的数据集。

2.在创建viewHolder时,创建自定义的viewHolder。

3.在绑定数据时,将对应的data object传给对应的viewHolder。

核心方法onCreateViewHolder:

调用时机:每个viewHolder被创建时(不一定每个都创建)

recyclerView有复用viewHolder的机制,即同一个类型的viewHolder不会一直重复创建。尤其是整个recylerView只有一种viewHolder时,在第一次填满整个屏幕后通常就不会再创建viewHolder了,而是通过重复绑定数据来刷新视图,给用户一种不断滑动的感觉。

因此在创建viewHolder时,我们只需要把viewHolder inflate出来,并返回即可。

核心方法onBindViewHolder:

调用时机:每个viewHolder被绑定数据时(每个都被绑数据)

从刚才的描述可以得知,数据绑定这一操作是贯彻在滑动过程中的。该方法调用时会传入当前的viewHolder和当前viewHolder在整个recyclerView的位置。

因此在绑定数据时,我们只需要执行每个viewHolder的bindData即可。

4.设置recylerView

private void initData() {
        // 填充数据
        mockData();
        // 创建adapter 必须
        ListViewAdapter listViewAdapter = new ListViewAdapter(itemDTOList);
        // 设置recyclerView的排列模式 必须
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(linearLayoutManager);
        // 设置adapter 必须
        mRecyclerView.setAdapter(listViewAdapter);
    }

recylerView必须设置的两个元素:排列模式和adapter,否则无法正确运行。