Android RecyclerView
介绍
RecyclerView
是 Android 的一个高级视图组件,旨在显示大量数据的列表或网格。相比于传统的 ListView
,RecyclerView
提供了更多的功能和灵活性。
Adapter
Adapter
是 RecyclerView
的数据源,负责将数据绑定到 ViewHolder
上。常见的 Adapter
实现包括 RecyclerView.Adapter
和 RecyclerView.ViewHolder
。
ViewHolder
ViewHolder
是一个用于缓存视图的对象,可以减少视图的重复查找。它持有对视图的引用,提升性能。
LayoutManager
LayoutManager
负责测量和布局 RecyclerView
的子项。RecyclerView
提供了几种内置的 LayoutManager
,如 LinearLayoutManager
、GridLayoutManager
和 StaggeredGridLayoutManager
,也可以自定义 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) { |
| |
| View view = View.inflate(context, R.layout.fruit_item, null); |
| |
| |
| |
| return new MyViewHolder(view); |
| } |
| @Override |
| public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { |
| |
| String fruit = fruits.get(position); |
| holder.fruit.setText(fruit); |
| } |
| @Override |
| public int getItemCount() { |
| |
| return fruits.size(); |
| } |
| } |
| class MyViewHolder extends RecyclerView.ViewHolder{ |
| |
| TextView fruit; |
| public MyViewHolder(@NonNull View itemView) { |
| |
| 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); |
| |
| List<String> fruits = new ArrayList<>(); |
| fruits.add("苹果"); |
| fruits.add("香蕉"); |
| fruits.add("西瓜"); |
| fruits.add("芒果"); |
| |
| recyclerView = findViewById(R.id.recycler); |
| |
| recyclerView.setLayoutManager(new LinearLayoutManager(this)); |
| |
| |
| |
| |
| |
| recyclerView.setAdapter(new FruitRecyclerAdapter(this,fruits)); |
| |
| |
| DividerItemDecoration dividerItemDecoration = new DividerItemDecoration( |
| recyclerView.getContext(), |
| DividerItemDecoration.VERTICAL |
| ); |
| recyclerView.addItemDecoration(dividerItemDecoration); |
| |
| |
| |
| 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 点击事件
方法 一
| |
| @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(); |
| } |
| }); |
| |
| } |
| |
| 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> |
| |
方法二
| |
| 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); |
| } |
| } |
| |
| @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(); |
| } |
| }); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
方法三
修改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> |
为下拉加载绑定事件
| |
| 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=findViewById(R.id.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); |
| } |
| @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(); |
| } |
| 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; |
| } |
| } |
| |
| |
| 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); |
| } |
| } |
| 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) { |
| hasMoreData = false; |
| } |
| } |
总结
RecyclerView
是一个功能强大且灵活的视图组件,适用于处理复杂的数据展示需求。通过合理配置 Adapter
、ViewHolder
、LayoutManager
等组件,可以高效地展示和管理大量数据。同时,支持自定义布局、点击事件处理以及下拉刷新等功能
代码地址
https://gitee.com/lxj_dear/recycler-view
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!