Android RecyclerView

Android RecyclerView

介绍

RecyclerView 是 Android 的一个高级视图组件,旨在显示大量数据的列表或网格。相比于传统的 ListViewRecyclerView 提供了更多的功能和灵活性。

Adapter

AdapterRecyclerView 的数据源,负责将数据绑定到 ViewHolder 上。常见的 Adapter 实现包括 RecyclerView.AdapterRecyclerView.ViewHolder

ViewHolder

ViewHolder 是一个用于缓存视图的对象,可以减少视图的重复查找。它持有对视图的引用,提升性能。

LayoutManager

LayoutManager 负责测量和布局 RecyclerView 的子项。RecyclerView 提供了几种内置的 LayoutManager,如 LinearLayoutManagerGridLayoutManagerStaggeredGridLayoutManager,也可以自定义 LayoutManager

ItemDecoration

ItemDecoration 可以用于给 RecyclerView 的项添加装饰,比如边框、分隔线等。

ItemAnimator

ItemAnimator 负责 RecyclerView 的动画效果,比如添加、删除或移动项时的动画。

简单使用

添加依赖

    implementation 'androidx.recyclerview:recyclerview:1.1.0'

在布局中添加RecyclerView控件

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

为RecyclerView添加布局文件

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fruit_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:textSize="18sp"/>

定义适配器与ViewHolder

public class FruitRecyclerAdapter extends RecyclerView.Adapter<MyViewHolder> {
    private Context context;
    public List<String> fruits;
    public FruitRecyclerAdapter(Context context,List<String> fruits){
        this.context=context;
        this.fruits=fruits;
    }
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        //onCreateViewHolder 方法负责创建视图项。它通过 View.inflate 方法将 fruit_item.xml 布局文件转换成 View 对象,并将其传递给 MyViewHolder。
        View view = View.inflate(context, R.layout.fruit_item, null);
//存在显示不全使用下面方法创建
//原因是“View.inflate()的第三个参数(父视图)如果为null,则意味着不会应用父视图的布局参数”
//View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view,parent,false);
        return new MyViewHolder(view);
    }
    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        //onBindViewHolder 方法负责将数据绑定到视图项上。它获取当前项的数据并设置到 MyViewHolder 中对应的 TextView 控件上。
        String fruit = fruits.get(position);
        holder.fruit.setText(fruit);
    }
    @Override
    public int getItemCount() {
        //getItemCount 方法返回数据集中项的总数,用于确定 RecyclerView 需要显示多少个视图项。
        return fruits.size();
    }
}
class MyViewHolder extends RecyclerView.ViewHolder{
    //自定义的 ViewHolder 类,继承自 RecyclerView.ViewHolder,用于缓存视图组件,避免重复调用 findViewById。
    TextView fruit;
    public MyViewHolder(@NonNull View itemView) {
        //MyViewHolder 构造函数,初始化 TextView 控件。
        super(itemView);
        fruit = itemView.findViewById(R.id.fruit_text);
    }
}

设置RecyclerView

private RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
		//为RecyclerView添加数据集
        List<String> fruits = new ArrayList<>();
        fruits.add("苹果");
        fruits.add("香蕉");
        fruits.add("西瓜");
        fruits.add("芒果");

        recyclerView = findViewById(R.id.recycler);
        //设置 RecyclerView 的布局管理器为 LinearLayoutManager,这表示列表将以线性(垂直)方式显示。
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
		//recyclerView.setLayoutManager(new LinearLayoutManager(this,RecyclerView.HORIZONTAL,false)); //这表示列表将以线性(水平)方式显示。false为是否倒序
		//recyclerView.setLayoutManager(new GridLayoutManager(this,2,RecyclerView.VERTICAL,false));//列表将以网格(垂直)方式显示,2表示俩列
		//recyclerView.setLayoutManager(new GridLayoutManager(this,2,RecyclerView.HORIZONTAL,false));//列表将以网格(水平)方式显示,2表示俩行
        
        //设置 RecyclerView 的适配器
        recyclerView.setAdapter(new FruitRecyclerAdapter(this,fruits));
        
        // 添加系统默认的横向分隔线
        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
                recyclerView.getContext(),
                DividerItemDecoration.VERTICAL
        );
        recyclerView.addItemDecoration(dividerItemDecoration);
        //-----      如果需要自定义分动画请自行百度      -----
        
        // 配置 ItemAnimator(动画)
        DefaultItemAnimator itemAnimator = new DefaultItemAnimator();
        itemAnimator.setAddDuration(1000); // 设置添加动画的持续时间
        itemAnimator.setRemoveDuration(1000); // 设置移除动画的持续时间

        mRecyclerView.setItemAnimator(itemAnimator);
        //-----      如果需要自定义分动画请自行百度      -----
		
    }

使用自定义

添加实体类

@Data
@AllArgsConstructor
public class Student {
    String name;
    int age;
    String sex;
}

添加布局文件

<?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">
    <TextView
        android:id="@+id/name"
        android:layout_marginHorizontal="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/sex"
        android:layout_marginHorizontal="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/age"
        android:layout_marginHorizontal="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>	

修改适配器和viewholder

public class FruitRecyclerAdapter extends RecyclerView.Adapter<MyViewHolder> {

    private Context context;
    public List<Student> Students;
    public FruitRecyclerAdapter(Context context,List<Student> Students){
        this.context=context;
        this.Students=Students;
    }
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            //-----   修改 -----
        View view = View.inflate(context, R.layout.layout_student_list, null);
            //-----   修改 -----
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        //-----   修改 -----
        Student student = Students.get(position);
        holder.name.setText(student.getName());
        holder.age.setText(String.valueOf(student.getAge()));
        holder.sex.setText(student.getSex());
        //-----   修改 -----
    }

    @Override
    public int getItemCount() {
        return Students.size();
    }
}
class MyViewHolder extends RecyclerView.ViewHolder{
        //-----   修改 -----
    TextView name;
    TextView age;
    TextView sex;
    public MyViewHolder(@NonNull View itemView) {
        super(itemView);
        name = itemView.findViewById(R.id.name);
        age = itemView.findViewById(R.id.age);
        sex = itemView.findViewById(R.id.sex);
    }
        //-----   修改 -----
}

修改activity

//-----    修改   ------
List<Student> students=new ArrayList<>();
students.add(new Student("张三",21,"男"));
students.add(new Student("李四",21,"女"));
students.add(new Student("王五",21,"男"));
//-----    修改   ------
/*
	省略。。。
*/
//-----    修改   ------
recyclerView.setAdapter(new FruitRecyclerAdapter(this,students));
//-----    修改   ------

RecyclerView 点击事件

方法 一

//在适配器中的onBindViewHolder添加代码
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
	Student student = Students.get(position);
	holder.name.setText(student.getName());
	holder.age.setText(String.valueOf(student.getAge()));
	holder.sex.setText(student.getSex());
	//-----     添加代码     -----
	holder.linearLayout.setOnClickListener(new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			Toast.makeText(context, "点击了姓名为:"+student.getName()+"的学生", Toast.LENGTH_SHORT).show();
		}
	});
	//-----     添加代码     -----
}
//修改ViewHolder
class MyViewHolder extends RecyclerView.ViewHolder{
    TextView name;
    TextView age;
    TextView sex;
	//-----     添加代码     -----
    LinearLayout linearLayout;
	//-----     添加代码     -----
    public MyViewHolder(@NonNull View itemView) {
        super(itemView);
        name = itemView.findViewById(R.id.name);
        age = itemView.findViewById(R.id.age);
        sex = itemView.findViewById(R.id.sex);
	//-----     添加代码     -----
        linearLayout=itemView.findViewById(R.id.itemsId);
	//-----     添加代码     -----
    }
}
//修改布局文件
<?xml version="1.0" encoding="utf-8"?>
<!--  在代码中删除下面注释,xml中控件内部不支持注释 -->
<LinearLayout
	//-----     添加代码     -----
    android:id="@+id/itemsId"
	//-----     添加代码     -----
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
    <TextView
        android:id="@+id/name"
        android:layout_marginHorizontal="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/sex"
        android:layout_marginHorizontal="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/age"
        android:layout_marginHorizontal="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

方法二

//修改viewholder
class MyViewHolder extends RecyclerView.ViewHolder{
    TextView name;
    TextView age;
    TextView sex;
    public MyViewHolder(@NonNull View itemView) {
        super(itemView);
        name = itemView.findViewById(R.id.name);
        age = itemView.findViewById(R.id.age);
        sex = itemView.findViewById(R.id.sex);

    }
    public void bind(Student student, int position, OnItemClickListener listener) {
        // 设置数据
        name.setText(student.getName());
        age.setText(String.valueOf(student.getAge()));
        sex.setText(student.getSex());

        // 设置点击事件
        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (listener != null) {
                    listener.onItemClick(position);
                }
            }
        });
    }

    // 定义一个接口用于回调点击事件
    public interface OnItemClickListener {
        void onItemClick(int position);
    }
}
//修改适配器onBindViewHolder方法
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
	holder.bind(Students.get(position), position, new MyViewHolder.OnItemClickListener() {
		@Override
		public void onItemClick(int position) {
			Toast.makeText(context,Students.get(position).getName(), Toast.LENGTH_SHORT).show();
         }
    });
}
    /*
    	//可以改写为
    	//定义全局属性 
    	private OnItemClickListener listener;
    	public FruitRecyclerAdapter(Context context,List<Student> Students,OnItemClickListener listener){
            this.context=context;
            this.Students=Students;
            this.listener=listener;
        }
        //修改适配器onBindViewHolder方法
        @Override
        public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
            holder.bind(Students.get(position), position,listener);
        }	
        //在activity中绑定适配器时改为
        recyclerView.setAdapter(new FruitRecyclerAdapter(this,students, new MyViewHolder.OnItemClickListener() {
			@Override
			public void onItemClick(int position) {
				Toast.makeText(this,Students.get(position).getName(), Toast.LENGTH_SHORT).show();
         	}
    	}));
    */

方法三

修改RecyclerView源码,在里面实现点击事件

RecyclerView 下拉刷新

添加依赖

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0'

用SwipeRefreshLayout将RecyclerView包裹

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
       android:id="@+id/swipeRefreshLayout"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

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

   </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

为下拉加载绑定事件

//将Students与adapter设置为全局变量
public class MainActivity extends AppCompatActivity {
//-----     设置为全局变量      -----
    private RecyclerView recyclerView;
    private SwipeRefreshLayout swipeRefreshLayout;
    private List<Student> students;
    private RecyclerView.Adapter adapter;
//-----     设置为全局变量      -----
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
		
//-----     修改      -----
        students=new ArrayList<>();
//-----     修改      -----
        
        /*
        	省略。。。
        */
//-----     修改      -----
        adapter =  new FruitRecyclerAdapter(this,students);
        recyclerView.setAdapter(adapter);
//-----     修改      -----
        
//swipeRefreshLayout绑定控件
swipeRefreshLayout=findViewById(R.id.swipeRefreshLayout);
// 设置 SwipeRefreshLayout 的刷新监听
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
	@Override
    public void onRefresh() {
        // 这里进行下拉刷新操作
        refreshData();
   	}
});

	//添加函数
	private void refreshData() {
        // 模拟网络请求或数据加载
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                students.clear();
                loadData(); // 重新加载数据
                swipeRefreshLayout.setRefreshing(false); // 结束刷新
            }
        }, 2000); // 模拟延迟2秒
    }
    @SuppressLint("NotifyDataSetChanged")
    private void loadData() {
        // 模拟加载数据
        for (int i = 0; i < 5; i++) {
            students.add(new Student("姓名"+(i+1),20+(i%5),i%2==0?"男":"女"));
        }
        adapter.notifyDataSetChanged();
    }
    @SuppressLint("NotifyDataSetChanged")
    private void loadData() {
        // 模拟加载数据
        for (int i = 0; i < 5; i++) {
            students.add(new Student("姓名"+(i+1),20+(i%5),i%2==0?"男":"女"));
        }
        adapter.notifyDataSetChanged();
    }

RecyclerView上拉加载

添加回调接口

public interface LoadMoreCallback {
    void onLoadMore();
}

实现 EndlessScrollListener来监听滚动事件,并触发加载更多的数据

public class EndlessScrollListener extends RecyclerView.OnScrollListener {

    private LinearLayoutManager layoutManager;
    private boolean isLoading = false; // 是否正在加载数据
    private boolean isMoreDataAvailable = true; // 是否还有更多数据
    private LoadMoreCallback loadMoreCallback;//回调函数

    public EndlessScrollListener(LinearLayoutManager layoutManager, LoadMoreCallback loadMoreCallback) {
        this.layoutManager = layoutManager;
        this.loadMoreCallback = loadMoreCallback;
    }

    @Override
    public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        if (dy > 0) { // 只处理向下滚动的情况
            int visibleItemCount = layoutManager.getChildCount();
            int totalItemCount = layoutManager.getItemCount();
            int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();

            if (!isLoading && isMoreDataAvailable) {
                //检查我们是否需要加载更多数据
                if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount) {
                    isLoading = true;
                    if (loadMoreCallback != null) {
                        loadMoreCallback.onLoadMore(); 
                        // 加载更多
                    }
                }
            }
        }
    }

    public void setMoreDataAvailable(boolean moreDataAvailable) {
        this.isMoreDataAvailable = moreDataAvailable;
    }

    public void setLoading(boolean loading) {
        this.isLoading = loading;
    }
}

activity绑定EndlessScrollListener滚动事件

//实现回调函数
public class MainActivity extends AppCompatActivity implements LoadMoreCallback {

    private SwipeRefreshLayout swipeRefreshLayout;
    private RecyclerView recyclerView;
    private MyAdapter adapter;
    private List<MyItem> itemList;
    private EndlessScrollListener scrollListener;
    private boolean hasMoreData = true; // 控制是否还有更多数据

    @Override
    protected void onCreate(Bundle savedInstanceState) {
     	
        //-----  省略  -----
        
        // 初始化并添加滚动监听器
        scrollListener = new EndlessScrollListener((LinearLayoutManager) recyclerView.getLayoutManager(), this);
        recyclerView.addOnScrollListener(scrollListener);
     	
        //-----  省略  -----
    }

    @Override
    public void onLoadMore() {
        if (hasMoreData) {
            // 模拟加载更多数据
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    loadMoreData();
                    scrollListener.setLoading(false); // 加载完成
                }
            }, 1000); // 模拟延迟1秒
        }
    }
    private void loadMoreData() {
        // 模拟加载更多数据
        int start = students.size();
        for (int i = start; i < start + 10; i++) {
            students.add(new Student("更多  -----  姓名"+(i+1),20+(i%5),i%2==0?"男":"女"));
        }
        adapter.notifyDataSetChanged();

        // 控制是否还有更多数据
        if (students.size() > 100) { // 假设100个数据后就没有更多数据了
            hasMoreData = false;
        }
    }

总结

RecyclerView 是一个功能强大且灵活的视图组件,适用于处理复杂的数据展示需求。通过合理配置 AdapterViewHolderLayoutManager 等组件,可以高效地展示和管理大量数据。同时,支持自定义布局、点击事件处理以及下拉刷新等功能

代码地址

https://gitee.com/lxj_dear/recycler-view

posted @ 2024-07-31 11:43  疾风不问归途  阅读(53)  评论(0)    收藏  举报