好的,我们来系统地学习 Android RecyclerView 的基本使用方法和常用功能。RecyclerView 是 ListView 和 GridView 的强大替代品,提供了更高的灵活性和性能。
一、基本使用步骤
使用 RecyclerView 需要五个核心组成部分,像一个团队协作:
-
RecyclerView自身:在布局中定义的视图容器。 -
数据源:一个包含所有要显示数据的列表(如
List<YourItem>)。 -
ViewHolder:描述单个列表项视图的类,用于缓存视图,提高性能。 -
Adapter:桥梁,将数据绑定到ViewHolder上。 -
LayoutManager:负责RecyclerView的布局排列方式(线性、网格、瀑布流)。
步骤 1:添加依赖
在 app/build.gradle 文件中添加依赖。
dependencies {
implementation "androidx.recyclerview:recyclerview:1.3.2"
}
步骤 2:在布局文件中添加 RecyclerView
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
步骤 3:创建列表项布局
创建单个列表项的布局文件 item_user.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="16dp">
<ImageView
android:id="@+id/ivAvatar"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:text="Name"
android:textSize="18sp" />
</LinearLayout>
步骤 4:创建数据模型 (Item Class)
创建一个数据类来表示列表中的每一项。
Kotlin:
data class User(val name: String, val avatarResId: Int)
Java:
public class User {
private String name;
private int avatarResId;
// 构造函数、Getter和Setter...
}
步骤 5:创建 ViewHolder
创建一个继承自 RecyclerView.ViewHolder 的类,用于持有列表项视图。
Kotlin:
class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val tvName: TextView = itemView.findViewById(R.id.tvName)
private val ivAvatar: ImageView = itemView.findViewById(R.id.ivAvatar)
fun bind(user: User) {
tvName.text = user.name
ivAvatar.setImageResource(user.avatarResId)
}
}
Java:
public class UserViewHolder extends RecyclerView.ViewHolder {
TextView tvName;
ImageView ivAvatar;
public UserViewHolder(@NonNull View itemView) {
super(itemView);
tvName = itemView.findViewById(R.id.tvName);
ivAvatar = itemView.findViewById(R.id.ivAvatar);
}
public void bind(User user) {
tvName.setText(user.getName());
ivAvatar.setImageResource(user.getAvatarResId());
}
}
步骤 6:创建 Adapter
创建继承自 RecyclerView.Adapter 的适配器,这是核心部分。
Kotlin:
class UserAdapter(private val userList: List<User>) : RecyclerView.Adapter<UserViewHolder>() {
// 创建新 ViewHolder(当没有可复用的 ViewHolder 时调用)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_user, parent, false)
return UserViewHolder(itemView)
}
// 将数据绑定到 ViewHolder 上
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
val currentUser = userList[position]
holder.bind(currentUser)
}
// 返回数据源的总数
override fun getItemCount(): Int {
return userList.size
}
}
Java:
public class UserAdapter extends RecyclerView.Adapter<UserViewHolder> {
private List<User> userList;
public UserAdapter(List<User> userList) {
this.userList = userList;
}
@NonNull
@Override
public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_user, parent, false);
return new UserViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
User currentUser = userList.get(position);
holder.bind(currentUser);
}
@Override
public int getItemCount() {
return userList.size();
}
}
步骤 7:在 Activity/Fragment 中组装
在 MainActivity 中,初始化所有部件并将它们连接起来。
Kotlin:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView: RecyclerView = findViewById(R.id.recyclerView)
// 1. 准备数据
val userList = listOf(
User("Alice", R.drawable.avatar1),
User("Bob", R.drawable.avatar2),
User("Charlie", R.drawable.avatar3)
)
// 2. 创建适配器,并传入数据
val adapter = UserAdapter(userList)
// 3. 将适配器设置给 RecyclerView
recyclerView.adapter = adapter
// 4. 设置布局管理器(必须设置!)
recyclerView.layoutManager = LinearLayoutManager(this)
// 可选:添加默认的动画效果
recyclerView.itemAnimator = DefaultItemAnimator()
}
}
Java:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.recyclerView);
// 1. 准备数据
List<User> userList = new ArrayList<>();
userList.add(new User("Alice", R.drawable.avatar1));
userList.add(new User("Bob", R.drawable.avatar2));
userList.add(new User("Charlie", R.drawable.avatar3));
// 2. 创建适配器,并传入数据
UserAdapter adapter = new UserAdapter(userList);
// 3. 将适配器设置给 RecyclerView
recyclerView.setAdapter(adapter);
// 4. 设置布局管理器(必须设置!)
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// 可选:添加默认的动画效果
recyclerView.setItemAnimator(new DefaultItemAnimator());
}
}
二、常用功能
1. 不同的布局管理器
-
线性布局(垂直/水平):
recyclerView.layoutManager = LinearLayoutManager(context) // 水平滚动 // recyclerView.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) -
网格布局:
// 2列的网格 recyclerView.layoutManager = GridLayoutManager(context, 2) -
瀑布流布局:
// 2列的瀑布流,需要每个item高度不一致 recyclerView.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
2. 添加点击事件
在 Adapter 的 onBindViewHolder 中为 itemView 设置点击监听。
在 Adapter 中:
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
val currentUser = userList[position]
holder.bind(currentUser)
// 设置点击事件
holder.itemView.setOnClickListener {
// 通过接口回调给Activity处理
listener.onItemClick(currentUser)
}
}
// 定义回调接口
interface OnItemClickListener {
fun onItemClick(user: User)
}
在 Activity 中实现接口:
class MainActivity : AppCompatActivity(), UserAdapter.OnItemClickListener {
// ... 其他代码 ...
override fun onItemClick(user: User) {
// 处理点击事件,例如跳转到详情页或显示Toast
Toast.makeText(this, "Clicked: ${user.name}", Toast.LENGTH_SHORT).show()
}
}
// 创建Adapter时,将this(即Activity)作为listener传入
val adapter = UserAdapter(userList, this)
3. 动态更新数据
不要直接修改原始列表并调用 notifyDataSetChanged(),这样效率低且没有动画。
推荐做法:
// 在Adapter中维护一个可变的列表
private var userList = mutableListOf<User>()
set(value) {
field = value
notifyDataSetChanged() // 全量更新,简单但效率低
}
// 更高效的方法:使用DiffUtil(见下节)
fun updateData(newList: List<User>) {
val diffResult = DiffUtil.calculateDiff(UserDiffCallback(this.userList, newList))
this.userList.clear()
this.userList.addAll(newList)
diffResult.dispatchUpdatesTo(this)
}
4. 高性能数据更新 - DiffUtil
DiffUtil 可以计算新旧数据集的差异,并只更新变化的项,伴有动画。
class UserDiffCallback(
private val oldList: List<User>,
private val newList: List<User>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldList.size
override fun getNewListSize(): Int = newList.size
// 判断两个item是否是同一个对象(例如id相同)
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition].id == newList[newItemPosition].id
}
// 判断两个item的内容是否相同
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
}
5. 添加头部和底部
可以通过在 Adapter 中创建不同的 viewType 来实现。
- 修改
getItemViewType根据位置返回不同的类型。 - 在
onCreateViewHolder中根据viewType创建不同的ViewHolder。 - 在
getItemCount中返回数据源大小 + 2(头尾)。 - 在
onBindViewHolder中根据位置和类型绑定数据。
6. 下拉刷新
使用 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/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
代码:
swipeRefreshLayout.setOnRefreshListener {
// 执行刷新数据的操作
fetchNewData()
// 数据获取完成后,停止刷新动画
swipeRefreshLayout.isRefreshing = false
}
总结
| 核心组件 | 作用 | 关键方法/类 |
|---|---|---|
| RecyclerView | 列表容器 | 在布局中定义 |
| Adapter | 数据与视图的桥梁 |
onCreateViewHolder, onBindViewHolder, getItemCount
|
| ViewHolder | 缓存列表项视图 | 继承自 RecyclerView.ViewHolder
|
| LayoutManager | 控制布局排列 |
LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager
|
| ItemDecoration | 绘制分割线 | DividerItemDecoration |
| ItemAnimator | 项动画 | DefaultItemAnimator |
| DiffUtil | 高效更新数据 | DiffUtil.calculateDiff() |
掌握这些基本用法和常用功能,你就能应对绝大多数列表展示的需求了。RecyclerView 的强大之处在于其高度的可定制性,你可以通过自定义 ItemDecoration、ItemAnimator 和 LayoutManager 来实现非常复杂和炫酷的列表效果。