RecyclerView的基本用法、横向/纵向/网格/瀑布流布局显示及点击事件

本文介绍了RecyclerView在Android开发中的基本用法,包括如何实现纵向、横向、网格和瀑布流布局,以及设置点击事件。通过调整LayoutManager,可以轻松切换不同布局。同时,RecyclerView的点击事件处理不同于ListView,需在自定义适配器的onCreateViewHolder方法中注册。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ListView只能纵向显示而且还要优化(即手动写代码实现缓存好子项布局文件及其里面控件),而Recycler除了优化好这些,还可以实现横向/纵向/网格/瀑布流布局显示(关键:只需改RecyclerVIew.setLayoutManager(布局类对象实例)中的布局类对象,这个参数的布局不同,就可以实现不同子项显示方式:横向/纵向/网格/瀑布流布局

  • 纵向LinearLayoutManager.VERTICAL:

LinearLayoutManager默认VERTICAL排列,setLayoutManager(布局类对象实例)传入LinearLayoutManager实例对象即可

  • 横向LinearLayoutManager.HORIZONTAL:

先LinearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL),在setLayoutManager(布局类对象)传入LinearLayoutManager实例对象即可

  • 网格GridLayoutManager:

setLayoutManager(布局类对象实例)传入GridLayoutManager实例对象即可,可先为GridLayoutManager实例对象设置点属性先

  • 瀑布流StaggeredGridLayoutManager:

setLayoutManager(布局类对象实例)传入StaggeredGridLayoutManager实例对象即可,StaggeredGridLayoutManager也可以设置瀑布流的排列是VERTICAL还是HORIZONTAL)

  1. RecyclerView的基本用法:

①打开app/build.gradle文件,在dependencies闭包内添加RecyclerView的依赖:

implementation 'com.android.support:recyclerview-v7:28.0.0'(V7:28.0.0仅仅是版本),可以通过Android Studio的Design视图直接添加RecyclerView,就会自动提示添加依赖了

②在要使用RecyclerView的XML中添加RecyclerView控件

<android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

<android.support.v7.widget.RecyclerView这里要用完整的路径

③定义实体类,作为子项里显示的数据的载体

public class Fruit {
    private String name;

    private int imageId;

    public Fruit(String name, int imageId) {
        this.name = name;
        this.imageId = imageId;
    }

    public String getName() {
        return name;
    }

    public int getImageId() {
        return imageId;
    }
}

④自定义子项布局(这里不同,则子项的样式也不同,而改setLayoutManager(***LayoutManager)仅仅是子项的布局和排列不同)

fruit_item.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"
    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

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

⑤自定义适配器类xxxAdapter,并继承RecyclerView.Adapter<泛型为xxxAdapter.ViewHolder>(xxxAdapter.ViewHolder为自定义适配器的静态内部类,用于缓存子项控件的),并重写onCreateViewHolder()、onBindViewHolder()、 getItemCount()

  • onCreateViewHolder():创建并返回ViewHolder实例,并且参数是动态加载进来的子项布局
  • onBindViewHolder:对RecyclerView的子项的数据进行赋值,当子项滚到屏幕都会被调用
    参数说明:
    ViewHolder viewHolder:缓存了子项中控件的静态内部类,这里是ImageView fruitImage; TextView fruitName;
    int i:i是滚入刚到屏幕内子项的编号
  • getItemCount():返回RecyclerView子项总数
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
    private List<Fruit> mFruitList;//用于存放数据的实体类数组

    //定义内部类ViewHolder,并继承RecyclerView.ViewHolder
    // 作用:用于缓存RecyclerView的子项布局文件中控件
    static class ViewHolder extends RecyclerView.ViewHolder{
        ImageView fruitImage;       //用于子项中图片控件的缓存
        TextView fruitName;         //用于子项中名字控件的缓存

        //ViewHolder构造函数,findViewById()获取子项布局中控件,然后缓存
        // 参数View itemView通常是RecyclerView的子项的最外层布局,或者就是子项布局
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            fruitImage=(ImageView)itemView.findViewById(R.id.fruit_image);
            fruitName=(TextView)itemView.findViewById((R.id.fruit_name));
        }
    }

    //自定义适配器构造函数
    //参数List<Fruit> fruitList是要传入的数据
    public FruitAdapter(List<Fruit> fruitList){
        mFruitList=fruitList;
    }

    //onCreateViewHolder():创建并返回ViewHolder实例,并且参数是动态加载进来的子项布局
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        //动态加载布局
        View view= LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.fruit_item,viewGroup,false);
        //创建ViewHolder实例,参数为刚加载进来的子项布局
        ViewHolder viewHolder=new ViewHolder(view);//这样,子项布局里面的控件就缓存到了ViewHolder

        return viewHolder;
    }

    //onBindViewHolder:对RecyclerView的子项的数据进行赋值,当子项滚到屏幕都会被调用
    //参数说明:
    //ViewHolder viewHolder:缓存了子项中控件的静态内部类,这里是ImageView fruitImage; TextView fruitName;
    //int i:i是滚入刚到屏幕内子项的编号

    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        Fruit fruit=mFruitList.get(i);      //获取实体类数组中数据
        //将数据bind到子项中控件(子项控件已缓存到了ViewHolder了)
        viewHolder.fruitName.setText(fruit.getName());
        viewHolder.fruitImage.setImageResource(fruit.getImageId());
    }

    //作用:返回RecyclerView子项总数
    @Override
    public int getItemCount() {
        return mFruitList.size();
    }
}

⑥使用:

* 思路还是:

* 数据通过适配器Adapter对象(构造参数传入)(即数据放进Adapter对象)

* 仅仅多了这个:RecyclerView.setLayoutManager(***LayoutManager)添加布局管理器                                 

* 然后使用RecyclerView.setAdapter(apdapter)将适配器对象传给RecyclerView对象

public class MainActivity extends AppCompatActivity {

    private List<Fruit> fruitList=new ArrayList<>();//用于子项数据的数组
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initFruits();//初始化数据

        RecyclerView recyclerView=(RecyclerView)findViewById(R.id.recycler_view);
        //设置RecyclerView的布局管理,布局管理者不同,RecyclerView的排列就不同
        /*横向滚动
        LinearLayoutManager layoutManager=new LinearLayoutManager(this);//LinearLayout默认VERTICAL排列
        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);//将排列方式设为水平
        */
        /*瀑布流滚动*/
        //StaggeredGridLayoutManager layoutManager=new StaggeredGridLayoutManager(3,1);

        /*网格RecyclerView*/
        GridLayoutManager layoutManager=new GridLayoutManager(this,4,0,false);

        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter fruitAdapter=new FruitAdapter(fruitList);//创建适配器对象,并传入数据
        recyclerView.setAdapter(fruitAdapter);//为RecyclerView添加带有数据的适配器,从而传给RecyclerView
    }

    private void initFruits() {
        for (int i = 0; i < 2; i++) {
            Fruit apple = new Fruit("Apple", R.drawable.apple_pic);
            fruitList.add(apple);
            Fruit banana = new Fruit("Banana", R.drawable.banana_pic);
            fruitList.add(banana);
            Fruit orange = new Fruit("Orange", R.drawable.orange_pic);
            fruitList.add(orange);
            Fruit watermelon = new Fruit("Watermelon", R.drawable.watermelon_pic);
            fruitList.add(watermelon);
            Fruit pear = new Fruit("Pear", R.drawable.pear_pic);
            fruitList.add(pear);
            Fruit grape = new Fruit("Grape", R.drawable.grape_pic);
            fruitList.add(grape);
            Fruit pineapple = new Fruit("Pineapple", R.drawable.pineapple_pic);
            fruitList.add(pineapple);
            Fruit strawberry = new Fruit("Strawberry", R.drawable.strawberry_pic);
            fruitList.add(strawberry);
            Fruit cherry = new Fruit("Cherry", R.drawable.cherry_pic);
            fruitList.add(cherry);
            Fruit mango = new Fruit("Mango", R.drawable.mango_pic);
            fruitList.add(mango);
        }
    }

这里

LinearLayoutManager layoutManager=new LinearLayoutManager(this);//LinearLayout默认VERTICAL排列
recyclerView.setLayoutManager(layoutManager);

.实现的是纵向滚动RecyclerView,和ListVIew差不多

只需改RecyclerVIew.setLayoutManager(布局类对象实例)中的布局类对象,这个参数的布局不同,就可以实现不同子项显示方式:横向/纵向/网格/瀑布流布局

所以:

  • 横向滚动:只需将LinearLayoutManager默认的VERTICAL排列改成HORIZONTAL就行了

LinearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);//设置排列方式为水平
 

...

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initFruits();//初始化数据

        RecyclerView recyclerView=(RecyclerView)findViewById(R.id.recycler_view);
        //设置RecyclerView的布局管理,布局管理者不同,RecyclerView的排列就不同
        LinearLayoutManager layoutManager=new LinearLayoutManager(this);//LinearLayout默认VERTICAL排列
        
        LinearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);//设置排列方式为水平

        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter fruitAdapter=new FruitAdapter(fruitList);//创建适配器对象,并传入数据
        recyclerView.setAdapter(fruitAdapter);//为RecyclerView添加带有数据的适配器,从而传给RecyclerView
    }

...
  • 瀑布流RecycleeView:只需改RecyclerVIew.setLayoutManager(布局类对象实例)中的布局类对象改为StaggeredGridLayoutManager即可
...
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initFruits();//初始化数据

        RecyclerView recyclerView=(RecyclerView)findViewById(R.id.recycler_view);
        //设置RecyclerView的布局管理,布局管理者不同,RecyclerView的排列就不同

        
        StaggerGridLayoutManager layoutManager=new StaggerGridLayoutManager(3,StaggerGridLayoutManager.VERTICAL);//创建3列,垂直排列的瀑布流对象
        recyclerView.setLayoutManager(layoutManager);
        
        FruitAdapter fruitAdapter=new FruitAdapter(fruitList);//创建适配器对象,并传入数据
        recyclerView.setAdapter(fruitAdapter);//为RecyclerView添加带有数据的适配器,从而传给RecyclerView
    }

...
  • 网格布局:只需改RecyclerVIew.setLayoutManager(布局类对象实例)中的布局类对象改为GridLayoutManager即可

GridLayoutManager layoutManager=new GridLayoutManager(this,4,0,false);

2. RecyclerView的点击事件:

RecyclerView并没有ListView那setOnItemClickListener()方法,因为这个方法很鸡肋,注册的是子项的点击事件,当如果要点击子项中具体某个控件时,可以实现但麻烦。

所以RecyclerView直接摒弃子项点击事件的监听器,所有的点击事件都有具体View自己去注册。

RecyclerView注册点击事件自定义适配器中的onCreateViewHolder(ViewGroup viewGroup, int i)中实现就行了,因为这个方法是用来动态加载子项布局文件创建ViewHolder对象并将子项布局及其里面控件缓存,所以可以为子项布局注册监听器也可为控件注册

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
    private List<Fruit> mFruitList;//用于存放数据的实体类数组

    //定义内部类ViewHolder,并继承RecyclerView.ViewHolder
    // 作用:用于缓存RecyclerView的子项布局文件中控件
    static class ViewHolder extends RecyclerView.ViewHolder{
        View fruitView;             //用于存储子项布局
        ImageView fruitImage;       //用于子项中图片控件的缓存
        TextView fruitName;         //用于子项中名字控件的缓存

        //ViewHolder构造函数,findViewById()获取子项布局中控件,然后缓存
        // 参数View itemView通常是RecyclerView的子项的最外层布局,或者就是子项布局
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            fruitView=itemView;
            fruitImage=(ImageView)itemView.findViewById(R.id.fruit_image);
            fruitName=(TextView)itemView.findViewById((R.id.fruit_name));
        }
    }

    //自定义适配器构造函数
    //参数List<Fruit> fruitList是要传入的数据
    public FruitAdapter(List<Fruit> fruitList){
        mFruitList=fruitList;
    }

    //onCreateViewHolder():创建并返回ViewHolder实例,并且参数是动态加载进来的子项布局
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        //动态加载布局
        View view= LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.fruit_item,viewGroup,false);
        //创建ViewHolder实例,参数为刚加载进来的子项布局
        final ViewHolder viewHolder=new ViewHolder(view);//这样,子项布局里面的控件就缓存到了ViewHolder
        
        /*为子项布局注册点击事件:*/
        viewHolder.fruitView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position=viewHolder.getAdapterPosition();       //获取点击子项的位置
                Fruit fruit=mFruitList.get(position);              //根据位置获取指定的数据实体
                Toast.makeText(v.getContext(),"触发的是子项的点击事件:"+fruit.getName(),Toast.LENGTH_SHORT).show();
            }
        });      
        
        /* 为子项中控件注册点击事件  */
        viewHolder.fruitImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position=viewHolder.getAdapterPosition();       //获取点击子项的位置
                Fruit fruit=mFruitList.get(position);              //根据位置获取指定的数据实体
                Toast.makeText(v.getContext(),"触发的是子项中图片的点击事件:"+fruit.getName(),Toast.LENGTH_SHORT).show();
            }
        });
        return viewHolder;
    }

    //onBindViewHolder:对RecyclerView的子项的数据进行赋值,当子项滚到屏幕都会被调用
    //参数说明:
    //ViewHolder viewHolder:缓存了子项中控件的静态内部类,这里是ImageView fruitImage; TextView fruitName;
    //int i:i是滚入刚到屏幕内子项的编号

    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        Fruit fruit=mFruitList.get(i);      //获取实体类数组中数据
        //将数据bind到子项中控件(子项控件已缓存到了ViewHolder了)
        viewHolder.fruitName.setText(fruit.getName());
        viewHolder.fruitImage.setImageResource(fruit.getImageId());
    }

    //作用:返回RecyclerView子项总数
    @Override
    public int getItemCount() {
        return mFruitList.size();
    }
}

注意:当子项注册了点击事件,而里面有些控件没有。点击这些没注册的控件,触发的是子项布局点击事件,因为会被最外层布局(注册了点击事件)捕获到的

所以这里我注册了子项点击事件,而TextView控件没有,就会触发子项的点击。

   

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值