Android学习之RecyclerView的使用

前言

使用RecyclerView的好处不必多说,有更好的性能表现,更好的拓展性等等。比起ListView,更推荐使用RecyclerView。

Android Studio中的准备工作

首先在activity_main.xml的design布局中找到Recycler并点击其右侧的下载图标执行依赖导入。
在这里插入图片描述
若找不到,可在build.gradle(有2个,选字最多的那个)的dependencies中,加入以下一行代码
implementation 'androidx.recyclerview:recyclerview:1.1.0'


垂直滚动

创建MyItem.java类

用于列表中每一个item实例持有其自身的文本和图片id。

package com.example.recyclerviewdemo;

public class MyItem {
    private String name;
    private int imageId;
    public MyItem(String name, int imageId){
        this.name=name;
        this.imageId=imageId;
    }

    public String getName(){
        return name;
    }
    public int getImageId(){
        return imageId;
    }
}

创建myitem.xml布局文件

其中android:orientation="horizontal"指定每个item中的布局为水平布局,64dp则限制了ImageView的尺寸

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

    <ImageView
        android:id="@+id/item_image"
        android:layout_width="64dp"
        android:layout_height="64dp">
    </ImageView>

    <TextView
        android:id="@+id/item_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp">
    </TextView>

</LinearLayout>

为MyItem创建其独特的适配器MyItemAdapter.java

package com.example.recyclerviewdemo;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.List;

public class MyItemAdapter extends RecyclerView.Adapter<MyItemAdapter.ViewHolder>{
    private List<MyItem> myItemList;

    /**
     * 定义内部类ViewHolder 继承自 RecyclerView.ViewHolder
     */
    static class ViewHolder extends RecyclerView.ViewHolder{
        ImageView itemImage;
        TextView itemName;
        /**
         * 构造参数中传入参数view
         * @param view RecyclerView子项的最外层布局
         */
        public ViewHolder(View view){
            super(view);
            itemImage=view.findViewById(R.id.item_image);
            itemName=view.findViewById(R.id.item_name);
        }
    }

    /**
     * 传入数据源
     * @param itemList
     */
    public MyItemAdapter(List<MyItem> itemList){
        myItemList=itemList;
    }

    /**
     * 重写onCreateViewHolder方法,用于创建ViewHolder实例,并把加载出来的布局传入到构造函数中,最后将ViewHolder的实例返回
     * @param parent
     * @param viewType
     * @return
     */
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.myitem,parent,false);
        ViewHolder holder=new ViewHolder(view);
        return holder;
    }

    /**
     * 对RecyclerView子项的数据进行赋值,会在每个子项被滚动到屏幕内的时候执行
     * @param holder
     * @param position
     */
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        MyItem item=myItemList.get(position);
        holder.itemImage.setImageResource(item.getImageId());
        holder.itemName.setText(item.getName());
    }

    /**
     * 告诉RecyclerView有多少子项
     * @return
     */
    @Override
    public int getItemCount() {
        return myItemList.size();
    }
}

在MainActivity.java中加入相关代码

package com.example.recyclerviewdemo;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private List<MyItem> myItemList=new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化列表数据
        initItem();
        //获取RecyclerView的实例
        RecyclerView recyclerView=findViewById(R.id.recycler_view);
        //指定RecyclerView的布局方式
        LinearLayoutManager layoutManager=new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        //为RecyclerView设置Adapter
        MyItemAdapter adapter=new MyItemAdapter(myItemList);
        recyclerView.setAdapter(adapter);
    }

    private void initItem(){
        for (int i = 0; i < 30; i++) {
            MyItem item1=new MyItem("item1",R.drawable.icon);
            myItemList.add(item1);
            MyItem item2=new MyItem("item2",R.drawable.java);
            myItemList.add(item2);
        }
    }
}

运行效果


水平滚动

修改自定义布局文件myitem.xml

其中<!-- ->中的内容为说明代码的意图,请自行去除,否则可能无法通过编译

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" <!-- 设置item为垂直布局 -->
    android:layout_width="100dp" <!-- 设置item的宽度为100dp,防止有些item过宽 -->
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/item_image"
        android:layout_gravity="center_horizontal" <!-- 设置图片位于item水平居中 -->
        android:layout_width="64dp"
        android:layout_height="64dp">
    </ImageView>

    <TextView
        android:id="@+id/item_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" <!-- 设置文本位于item水平居中 -->
        android:layout_marginTop="10dp">  <!-- 设置文本与上方的图片间隔10dp -->
    </TextView>


</LinearLayout>

修改MainActivity.java

新增一句代码layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
此代码将设置布局管理器layoutManager的布局方向为水平

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化列表数据
        initItem();
        //获取RecyclerView的实例
        RecyclerView recyclerView=findViewById(R.id.recycler_view);
        //指定RecyclerView的布局方式 水平布局
        LinearLayoutManager layoutManager=new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);//!此句为新增
        recyclerView.setLayoutManager(layoutManager);
        //为RecyclerView设置Adapter
        MyItemAdapter adapter=new MyItemAdapter(myItemList);
        recyclerView.setAdapter(adapter);
    }

运行效果


实现瀑布流布局

由于Android已经为我们配置好了相关模板,因此我们只需要修改非常小一部分内容就能达到瀑布流布局的效果

修改myitem.xml代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent" <!-- 瀑布流布局的宽度根据列数自适应 -->
    android:layout_height="wrap_content"
    android:layout_margin="5dp" <!-- 每个item之间间隔5dp  -->
    >

    <ImageView
        android:id="@+id/item_image"
        android:layout_gravity="center_horizontal"
        android:layout_width="64dp"
        android:layout_height="64dp">
    </ImageView>

    <TextView
        android:id="@+id/item_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp">
    </TextView>


</LinearLayout>

修改MainActivity.java代码

新增以下方法,用于得到一个随机长度的字符串,用于item的文本显示

private String getRandomLengthName(String name){
        Random random=new Random();
        int length=random.nextInt(20)+1;
        StringBuilder builder=new StringBuilder();
        for (int i = 0; i < length; i++) {
            builder.append(name);
        }
        return builder.toString();
    }

修改以下代码
在OnCreate方法中修改
LinearLayoutManager layoutManager=new LinearLayoutManager(this);
StaggeredGridLayoutManager layoutManager=new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
用于指定RecyclerView的布局方式为 3列纵向瀑布流布局

在initItem方法中调用getRandomLengthName方法
修改后,MainActivity.java代码如下

package com.example.recyclerviewdemo;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import android.os.Bundle;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class MainActivity extends AppCompatActivity {
    private List<MyItem> myItemList=new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化列表数据
        initItem();
        //获取RecyclerView的实例
        RecyclerView recyclerView=findViewById(R.id.recycler_view);
        //指定RecyclerView的布局方式为 3列纵向瀑布流布局
        StaggeredGridLayoutManager layoutManager=new
                StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);
        //为RecyclerView设置Adapter
        MyItemAdapter adapter=new MyItemAdapter(myItemList);
        recyclerView.setAdapter(adapter);
    }

    private void initItem(){
        for (int i = 0; i < 30; i++) {
            MyItem item1=new MyItem(
                    getRandomLengthName("item1"),R.drawable.icon);
            myItemList.add(item1);
            MyItem item2=new MyItem(
                    getRandomLengthName("item2"),R.drawable.java);
            myItemList.add(item2);
        }
    }

    private String getRandomLengthName(String name){
        Random random=new Random();
        int length=random.nextInt(20)+1;
        StringBuilder builder=new StringBuilder();
        for (int i = 0; i < length; i++) {
            builder.append(name);
        }
        return builder.toString();
    }
}

运行效果


为RecyclerView添加OnClickListner实现单击事件监听

与ListView不同的是,RecyclerView没有提供类似于setOnItemClickListener()这样的注册监听器的方法,而是需要我们自己给子项具体的View去注册点击事件,所以实现起来稍微有点复杂。
这样做的好处是,我们可以知道用户单击了item中哪个部分,而ListView不行。ListView对于item中的按钮单击,处理起来远远没有RecycerView方便。所以RecyclerView直接去除了setOnItemClickListener()方法,所有的点击事件都由具体的View去注册。
#修改MyItemAdapter.java中的代码
在类ViewHolder新增成员View itemView;用于持有item自身的view。

/**
     * 定义内部类ViewHolder 继承自 RecyclerView.ViewHolder
     */
    static class ViewHolder extends RecyclerView.ViewHolder{
        View itemView;//新增
        ImageView itemImage;
        TextView itemName;
        /**
         * 构造参数中传入参数view
         * @param view RecyclerView子项的最外层布局
         */
        public ViewHolder(View view){
            super(view);
            itemView=view;//新增
            itemImage=view.findViewById(R.id.item_image);
            itemName=view.findViewById(R.id.item_name);
        }
    }

修改OnCreateViewHolder()方法
ViewHolder holder=new ViewHolder(view);
声明为final,final ViewHolder holder=new ViewHolder(view);这样匿名内部类中可以获取到holder变量

由于前边我们的item的viewholder可以持有自身的view,因此我们为item的view设置单击监听器,实现setOnClickListener()。同理,也为item的Image设置单击监听器。我们没有给item的TextView设置监听器,因此item的文本被单击之后,会被item的最外层布局捕获到,作为view的单击事件处理。

/**
     * 重写onCreateViewHolder方法,用于创建ViewHolder实例,并把加载出来的布局传入到构造函数中,最后将ViewHolder的实例返回
     * @param parent
     * @param viewType
     * @return
     */
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.myitem,parent,false);
        //声明为final,这样匿名内部类中也能获取
        final ViewHolder holder=new ViewHolder(view);
        //重写onClick方法,为item的视图设置单击监听器
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //获得被单击的item 的实例
                int position=holder.getAdapterPosition();
                MyItem item=myItemList.get(position);
                Toast.makeText(v.getContext(),"单击view,item名称为"+item.getName(),Toast.LENGTH_SHORT).show();
            }
        });
        //重写OnClick方法,为item的图片也设置单击监听器
        holder.itemImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position=holder.getAdapterPosition();
                MyItem item=myItemList.get(position);
                Toast.makeText(v.getContext(),"单击image,item名称为"+item.getName(),Toast.LENGTH_SHORT).show();
            }
        });
        return holder;
    }

运行效果

单击item的图片,Toast显示单击了Image

单击item的文本,Toast显示单击了View


资料参考自《第一行代码》作者:郭霖
由于本人才疏学浅,所以本文仅用于记录及分享相关用法,并将持续更新更多的用法

发布了19 篇原创文章 · 获赞 2 · 访问量 4181

猜你喜欢

转载自blog.csdn.net/c529283955/article/details/104120222
今日推荐