08 RecyclerView 列表¶
App 里最常见的界面就是"列表"(聊天记录、文章列表、设置项……)。RecyclerView 是官方高性能列表控件,核心思路:数据 + 适配器(Adapter) + 布局管理器。
8.1 添加依赖¶
app/build.gradle.kts 的 dependencies 里加上:
implementation("androidx.recyclerview:recyclerview:1.3.2")
8.2 布局里放 RecyclerView¶
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
8.3 单个条目的布局 item_article.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="vertical"
android:padding="16dp">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvDesc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="13sp"
android:layout_marginTop="4dp"
android:textColor="#888888" />
</LinearLayout>
8.4 数据类¶
public class Article {
public String title;
public String desc;
public Article(String title, String desc) {
this.title = title;
this.desc = desc;
}
}
8.5 适配器 Adapter(核心)¶
public class ArticleAdapter extends RecyclerView.Adapter<ArticleAdapter.ViewHolder> {
private List<Article> data;
private OnItemClickListener listener;
public interface OnItemClickListener {
void onItemClick(int position, Article article);
}
public ArticleAdapter(List<Article> data, OnItemClickListener listener) {
this.data = data;
this.listener = listener;
}
// ① 创建条目视图(布局 inflate 成 View)
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_article, parent, false);
return new ViewHolder(v);
}
// ② 把数据绑定到条目控件上
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Article item = data.get(position);
holder.tvTitle.setText(item.title);
holder.tvDesc.setText(item.desc);
holder.itemView.setOnClickListener(v -> {
if (listener != null) listener.onItemClick(position, item);
});
}
// ③ 条数
@Override
public int getItemCount() {
return data == null ? 0 : data.size();
}
// ViewHolder:缓存每个条目的控件引用,避免重复 findViewById
static class ViewHolder extends RecyclerView.ViewHolder {
TextView tvTitle, tvDesc;
ViewHolder(View itemView) {
super(itemView);
tvTitle = itemView.findViewById(R.id.tvTitle);
tvDesc = itemView.findViewById(R.id.tvDesc);
}
}
}
8.6 在 Activity 里装配¶
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 造点假数据
List<Article> list = new ArrayList<>();
list.add(new Article("第一章", "RecyclerView 入门"));
list.add(new Article("第二章", "Adapter 与 ViewHolder"));
list.add(new Article("第三章", "点击事件"));
RecyclerView rv = findViewById(R.id.rvList);
rv.setLayoutManager(new LinearLayoutManager(this)); // 纵向列表
ArticleAdapter adapter = new ArticleAdapter(list, (position, article) -> {
Toast.makeText(this, "点了:" + article.title, Toast.LENGTH_SHORT).show();
// 跳详情页可以在这里 startActivity + putExtra
});
rv.setAdapter(adapter);
}
}
8.7 换样式:改 LayoutManager 即可¶
// 横向滑动列表
rv.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
// 网格(比如 2 列)
rv.setLayoutManager(new GridLayoutManager(this, 2));
// 瀑布流(高度不一的卡片)
rv.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
8.8 更新数据¶
list.add(new Article("新条目", "……"));
adapter.notifyItemInserted(list.size() - 1); // 只刷新新增那条
// 或全量刷新:adapter.notifyDataSetChanged();
注意:改完数据一定要调用 notify 系列方法,否则界面不刷新。
本章练习:做一个 20 条数据的文章列表,点击条目 Toast 出标题;再试改成 2 列网格。