【RecyclerView系列】1. RecyclerView简介及基本用法

1,139 阅读3分钟

1 RecyclerView 简介

RecyclerView是Google官方提供的任何基于适配器显示的视图,可以实现普通列表(ListView),网格列表(GridView),瀑布流,以及各种自定义形式的多容器布局

RecyclerView样式与适配器等解耦:RecyclerView提供了插拔式体验,实现的Adapter适配器与显示样式设置高度解耦,在不改变Adapter适配器的前提下:

  • 通过设置不同的LayoutManager,就可以实现不同的布局展示样式
  • 通过设置不同的ItemDecoration,可以实现不同的间隔样式
  • 通过设置不同的ItemAnimator,可以实现不同的添加删除动画

例如:设置不同的LayoutManager,就可以实现不同的布局展示样式

  • 设置LinearLayoutManager布局管理器,RecyclerView展示的就是横向/纵向的列表
  • 设置GridLayoutManager布局管理器,RecyclerView展示的就是网格布局
  • 设置StaggeredGridLayoutManager布局管理器,RecyclerView展示的就是瀑布流样式的布局

1.1 RecyclerView 特点

  • 功能强大:实现列表、网格、瀑布流、自定义容器等功能
  • 垃圾回收机制:RecyclerView的内部实现了回收机制,无需我们考虑View的复用情况
  • ViewHolder规范:RecyclerView避免了ListView中自定义ViewHolder,给出了相应的规范
  • 取消了onItemClick等点击事件,需要自己手动去写

1.2 RecyclerView 涉及到的类

RecyclerView使用必须有的关键类:RecyclerView.ViewHolderRecyclerView.AdapterLayoutManager

  • RecyclerView.ViewHolder:用于定义RecyclerView中每个独立元素的显示的组件,创建时不关联数据,创建后会在RecyclerView.Adapter适配器的onBindViewHolder方法中为其关联数据
  • RecyclerView.Adapter:主要作用是创建RecyclerView.ViewHolder,并为其绑定数据
  • LayoutManager:布局管理器主要作用是负责排列各个元素组件,可以使用系统提供的线性布局管理器 LinearLayoutManager,网格布局管理器GridLayoutManager,瀑布流布局管理器StaggeredGridLayoutManager,也可以自定义实现各种奇形怪状的布局管理器,如自定义圆形的布局管理器

设置类:

  • ItemDecoration:用于设置每个item的间隔样式
  • ItemAnimator:用于设置item的动画效果,如添加动画、删除动画等

2 RecyclerView 的基本用法

在build.gradle的dependencies中添加RecyclerView的依赖库

dependencies {
    implementation "androidx.recyclerview:recyclerview:1.2.1"
    // For control over item selection of both touch and mouse driven selection
    implementation "androidx.recyclerview:recyclerview-selection:1.1.0"
}

在布局文件中使用RecyclerView

<?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=".activity.RecyclerViewActivity">

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

</LinearLayout>

根据需要定义RecyclerView每行所实现的xml布局(item布局)。my_item_view.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/img_ico"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_gravity="center"/>

    <TextView
        android:id="@+id/text_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="50dp"/>
</LinearLayout>

自定义适配器MyAdapterRecyclerView.java

public class MyAdapterRecyclerView extends RecyclerView.Adapter<MyAdapterRecyclerView.MyViewHolder> {

    private LayoutInflater mInflater;
    private List<ItemData> mDataItemLists;
    private RecyclerViewItemClick mRecyclerViewItemClick;

    public MyAdapterRecyclerView(Context context, List<ItemData> itemDataList) {
        mInflater = LayoutInflater.from(context);
        this.mDataItemLists = itemDataList;
    }

    /**
     * 创建Item视图,并返回相应的ViewHolder
     * @param parent
     * @param viewType
     * @return
     */
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.my_list_view, null);
        return new MyViewHolder(view);
    }

    /**
     * 绑定数据到正确的Item视图上
     * @param holder
     * @param position
     */
    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.imageView.setImageResource(mDataItemLists.get(position).getImg());
        holder.textView.setText(mDataItemLists.get(position).getName());

        if (mRecyclerViewItemClick != null) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mRecyclerViewItemClick.onItemClick(position);
                }
            });

            holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    mRecyclerViewItemClick.onItemLongClick(position);
                    return false;
                }
            });
        }
    }

    /**
     * 返回Item数量
     * @return
     */
    @Override
    public int getItemCount() {
        return mDataItemLists.size();
    }

    /**
     * 绑定传进来的点击监听器
     * @param recyclerViewItemClick
     */
    public void setRecyclerViewItemClick(RecyclerViewItemClick recyclerViewItemClick){
        this.mRecyclerViewItemClick = recyclerViewItemClick;
    }
}

定义ViewHolder

/**
 * 定义ViewHolder
 */
public static class MyViewHolder extends RecyclerView.ViewHolder {

    public ImageView imageView;
    public TextView textView;

    public MyViewHolder(View itemView) {
        super(itemView);
        imageView = itemView.findViewById(R.id.img_ico);
        textView = itemView.findViewById(R.id.text_name);
    }
}

item点击事件接口

public interface RecyclerViewItemClick{
    /**
     * 点击事件
     * @param position
     */
    void onItemClick(int position);

    /**
     * 长按事件
     * @param position
     */
    void onItemLongClick(int position);
}

使用RecyclerView

  • 定义一个HashMap构成的列表,将数据以键值对的方式存放在里面
  • 构造Adapter对象,设置适配器
  • 将RecyclerView绑定到Adapter上
public class RecyclerViewActivity extends AppCompatActivity implements MyAdapterRecyclerView.RecyclerViewItemClick {

    private List<ItemData> mItemDataList;
    private RecyclerView mRecyclerView;
    private MyAdapterRecyclerView mMyAdapter;
    private final String[] names = {"深圳", "上海", "西安", "杭州", "深圳", "上海", "西安", "杭州", "深圳", "上海", "西安", "杭州",
            "深圳", "上海", "西安", "杭州", "深圳", "上海", "西安", "杭州", "深圳", "上海", "西安", "杭州"};
    private final int[] imgs = {R.drawable.person1,R.drawable.person2,R.drawable.person1,R.drawable.person2,R.drawable.person1, R.drawable.person2,
            R.drawable.person1,R.drawable.person2,R.drawable.person1,R.drawable.person2,R.drawable.person1,R.drawable.person2,
            R.drawable.person1,R.drawable.person2,R.drawable.person1,R.drawable.person2,R.drawable.person1, R.drawable.person2,
            R.drawable.person1,R.drawable.person2,R.drawable.person1,R.drawable.person2,R.drawable.person1,R.drawable.person2};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler_view);
        initItemData();
        initView();
    }

    private void initItemData() {
        mItemDataList = new ArrayList<ItemData>();
        for (int i = 0; i < names.length; i++) {
            ItemData itemData = new ItemData();
            itemData.setImg(imgs[i]);
            itemData.setName(names[i]);
            mItemDataList.add(itemData);
        }
    }

    private void initView() {
        mRecyclerView = findViewById(R.id.recycler_view);
        //使用线性布局
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        mMyAdapter = new MyAdapterRecyclerView(this ,mItemDataList);
        mMyAdapter.setRecyclerViewItemClick(this);
        mRecyclerView.setLayoutManager(layoutManager);
        mRecyclerView.setAdapter(mMyAdapter);
    }

    /**
     * 实现 MyAdapterRecyclerView.RecyclerViewItemClick 中的接口,实现点击事件
     * @param position
     */
    @Override
    public void onItemClick(int position) {
        Toast.makeText(this, "点击事件,第 "+ position + " 个ItemView", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onItemLongClick(int position) {
        Toast.makeText(this, "长按事件,第 "+ position + " 个ItemView", Toast.LENGTH_SHORT).show();
    }
}

效果图
device-2022-08-28-182239

代码地址:gitee.com/maojiu0825/…