跳转至

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 列网格。

🏠 返回总站