安卓开发--RecycleView

核心架构

作用

​​RecyclerView​​

负责视图回收和滚动管理的容器(方法setLayoutManager(),setAdapter())

​​Adapter​​

数据与视图的桥梁,决定内容显示(必须重写onCreateViewHolder,onBindViewHolder,getItemCount)

​​ViewHolder​​

缓存视图引用(减少findViewById开销),继承RecyclerView.viewHolder

​​LayoutManager​​

控制布局排列方式(线性/网格/瀑布流)

​​ItemDecoration​​

添加Item间隔/分割线(getItemOffsets(),onDraw())

​​ItemAnimator​​

处理增删改动画(DefaultItemAnimator,SimpleItemAnimator)

数据Data:List<>类型数据

可滚动的列表项集合:RecyclerView

UI界面的布局管理:Recyclerview.LayoutManager

RecyclerView连接数据的适配器:RecyclerView.Adapter

每个列表项布局:XML file

显示列表项的每个控件的信息:RecyclerView.ViewHolder

每个ViewGroup都有一个布局管理器,用于定位每一个列表项的位置,可以重用对于用户不可见的列表项。

内置的布局管理器,它们都继承自LayoutManager(LinearLayoutManager线性布局,GridLayoutManager表格布局,StaggeredGridLayout瀑布形式)

Adapter作为视图和数据之间的中介,管理在数据更改时创建,更新,添加和删除列表项。

ViewHolder为适配器准备每个列表项的视图和数据,它在XML资源布局文件中指定布局,实现点击功能

RecyclerView.Adapter需要重写以下三个方法

  1. onCreatViewHolder():此方法通过inflate()方法将列表项item布局编译为View对象,返回以这个对象为参数的ViewHolder对象
  2. onBindViewHolder():此方法主要将数据渲染到列表项的ViewHolder的View控件中
  3. getItemCount():此方法类似与ListView的BaseAdapter适配器的getCount()方法,即数据的总条目。

RecyclerView.Adapter本身没有ListView的OnItemClick点击事件的监听器。

解决办法:
方法一:设置ViewHolder的itemView的OnClick事件监听,通过setTag()存储itemView对象信息。
方法二(推荐):Adapter类自定义内部事件接口,定义事件处理的回调方法,参数为被点击item的位置;Activity或Fragment类实现或创建该接口的对象,实现回调方法;当item被点击时调用该接口的回调方法,将位置信息传递给回调方法。

方法三:实现RecyclerView的onItemTouchListener接口,通过GestureDetectorCompat类进行手势的拦截和响应,然后GestureDetectorCompat交给实现了OnGestureListener接口的SimpleOnGestureListenter实现,调用逻辑相对较为复杂。

简单实例(MainActivity.java & activity_main.xml & ltem_layout.xml & Fruit.java & FruitAdaptet.java)

MainActivity.java

package com.example.myapplication;

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

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


public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;


    //准备数据:list数据类型为泛型,把自己建的水果类填上
    private List<Fruit> fruits = new ArrayList<>(){
        {
            //list的add方法增加元素
            add(new Fruit("苹果",R.drawable.ic_launcher_background));
            add(new Fruit("苹果",R.drawable.ic_launcher_background));
            add(new Fruit("苹果",R.drawable.ic_launcher_background));
            add(new Fruit("苹果",R.drawable.ic_launcher_background));
            add(new Fruit("苹果",R.drawable.ic_launcher_background));
            add(new Fruit("苹果",R.drawable.ic_launcher_background));
            add(new Fruit("苹果",R.drawable.ic_launcher_background));
            add(new Fruit("苹果",R.drawable.ic_launcher_background));


        }
    };

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

        //获取视图
        recyclerView = findViewById(R.id.recycle_view);
        //拿到线性布局管理器
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        //给recyclerview设置线性布局管理器
        recyclerView.setLayoutManager(layoutManager);
        //设置方向
        layoutManager.setOrientation(RecyclerView.VERTICAL);
        //设置水平分割线
        recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));

        //初始化水果适配器
        FruitAdapter adapter = new FruitAdapter(fruits);//构造函数传参,把fruits传给FruitAdapter
        //給列表设置适配器
        recyclerView.setAdapter(adapter);

    }
}

activity_main.xml

<?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"
    android:orientation="vertical"
    android:padding="16dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycle_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="10dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
                />


</androidx.constraintlayout.widget.ConstraintLayout>

ltem_layout.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="wrap_content"
    android:orientation="horizontal"
    android:padding="10dp"
    >

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="64dp"
        android:layout_weight="1"
        android:layout_margin="5dp"
        />

    <TextView
        android:id="@+id/textview"
        android:layout_width="0dp"
        android:layout_height="64dp"
        android:layout_weight="5"
        android:textSize="18sp"
        android:layout_margin="5dp"
        android:gravity="center_vertical"
        android:text="TextView"
        />

</LinearLayout>

Fruit.java

package com.example.myapplication;

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;
    }
}

FruitAdaptet.java

package com.example.myapplication;

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 FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {

    //1.定义数据成员(List)类型,用于接收Activity调用适配器时传递数据,实现数据共享
    private List<Fruit> fruitsInAdapter;


    //2.构造函数
    public FruitAdapter(List<Fruit> fruitList) {
        this.fruitsInAdapter = fruitList;
    }

    //3.数据的总条目
    @Override
    public int getItemCount() {
        return fruitsInAdapter.size();
    }

    //4.布局:通过inflate方法将列表项item布局编译为view对象,返回以这个对象为参数的ViewHolder对象(就是创建viewholder)
    @NonNull
    @Override
    public FruitAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout,parent,false);
        return new ViewHolder(view);
    }

    //5.将数据渲染到列表项的ViewHolder的view控件中(就是绑定数据)
    @Override
    public void onBindViewHolder(@NonNull FruitAdapter.ViewHolder holder, int position) {
        //给第position条目 绑定数据(从0开始计数) 对应的数据是fruitInAdapter的position个元素 里面包含名称和图片id
        Fruit fruit = fruitsInAdapter.get(position);//里面包含名称和图片

        holder.textView.setText(fruit.getName());
        holder.imageView.setImageResource(fruit.getImageId());
    }

    
    //6.新建viewholder
    public static class ViewHolder extends  RecyclerView.ViewHolder {
        //说明每一个条目布局上的子View的 对象一一映射关系
        TextView textView;
        ImageView imageView;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            textView = itemView.findViewById(R.id.textview);
            imageView = itemView.findViewById(R.id.imageView);
        }
    }
}

代码的实现逻辑

1. 初始化阶段(Adapter 创建时)

调用顺序

  1. MainActivity 中创建 Adapter:FruitAdapter adapter = new FruitAdapter(fruits);将 MainActivity 的 fruits 列表通过构造函数传递给 FruitAdapter 的 fruitsInAdapter此时fruitsInAdapter 和 fruits 指向同一个 List 对象(数据共享)。

2. 列表首次加载时(RecyclerView 内部驱动)

方法调用顺序

  1. getItemCount()

    • RecyclerView 首先 调用此方法获取总项数(如 fruitsInAdapter.size())。

    • 作用:确定需要显示多少项。

  2. onCreateViewHolder(parent, viewType)

    • 对 每一项 调用此方法,创建对应的 ViewHolder

    • 内部逻辑
      View view = LayoutInflater.inflate(R.layout.item_layout, parent, false);
      return new ViewHolder(view);

      • 将 item_layout.xml 加载为 View 对象。

      • 创建 ViewHolder 并保存子视图(TextView 和 ImageView)。

  3. onBindViewHolder(holder, position)

    • 将数据绑定到 ViewHolder 的视图上。

    • 内部逻辑
      Fruit fruit = fruitsInAdapter.get(position); holder.textView.setText(fruit.getName()); holder.imageView.setImageResource(fruit.getImageId());

      • 从 fruitsInAdapter 获取当前位置的数据。

      • 将数据设置到 ViewHolder 的控件中。

3. 滚动列表时(复用 ViewHolder)

方法调用顺序

  1. 复用 ViewHolder

    • RecyclerView 复用已滚出屏幕的 ViewHolder 对象(跳过 onCreateViewHolder)。

  2. 直接调用 onBindViewHolder

    • 重新绑定新位置的数据到复用的 ViewHolder

4. 数据更新时(如添加/删除项)

调用顺序(以 notifyItemInserted() 为例):

  1. MainActivity 修改数据并通知 Adapter

    fruits.add(new Fruit(...));  // 修改数据
    adapter.notifyItemInserted(position); // 触发更新
  2. Adapter 内部流程

    • getItemCount() 被重新调用(获取最新数量)。

    • 对新项调用 onCreateViewHolder 或复用已有 ViewHolder

    • 对新项调用 onBindViewHolder 绑定数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值