listview,recycleview是怎么使用的,以及它的布局资源和控件有哪些

2 阅读10分钟

HeadLine 仿今日头条项目实战全解析

——ListView 与 RecyclerView 核心使用、布局资源与控件深度详解

作者:Android 实训课程学习笔记 字数:约 25000 字 截图数量:≥8 张(含项目结构、运行界面、布局文件、RecyclerView 多布局、ListView 对比、点击效果、下拉刷新等)


目录

  1. 项目背景与整体介绍
  2. 开发环境与技术栈
  3. 项目整体结构分析
  4. ListView 基础使用与完整实现 4.1 ListView 是什么 4.2 ListView 核心原理 4.3 ListView 完整代码实现 4.4 ListView 布局文件与控件详解 4.5 ListView 适配器与数据绑定 4.6 ListView 点击事件与优化
  5. RecyclerView 核心使用与深度解析 5.1 RecyclerView 出现的意义 5.2 RecyclerView 与 ListView 对比 5.3 RecyclerView 五件套:布局、Adapter、ViewHolder、LayoutManager、ItemDecoration 5.4 RecyclerView 完整代码实现 5.5 多布局类型实现(仿今日头条新闻样式) 5.6 下拉刷新与上拉加载
  6. 项目中所有布局资源详解 6.1 主页面布局 6.2 新闻条目单图布局 6.3 新闻条目三图布局 6.4 新闻条目纯文本布局 6.5 频道标签布局 6.6 分割线与样式资源
  7. 项目核心控件详解与使用方法 7.1 TextView 7.2 ImageView 7.3 RecyclerView / ListView 7.4 LinearLayout / RelativeLayout 7.5 SwipeRefreshLayout 7.6 TabLayout + ViewPager2
  8. 项目运行效果与截图展示
  9. 常见问题与解决方案
  10. 实验总结与收获

1. 项目背景与整体介绍

随着移动互联网的快速发展,新闻资讯类 App 已经成为人们日常生活中获取信息的重要工具。今日头条作为国内最具代表性的综合资讯平台,其界面结构清晰、交互流畅、列表展示高效,是 Android 开发者学习列表控件、UI 布局、数据绑定与性能优化的绝佳案例。

本次 HeadLine 仿今日头条项目,是老师在 Android 开发课程中布置的综合实训项目,旨在让学生掌握:

  • Android 基础 UI 布局
  • ListView 与 RecyclerView 列表控件的使用
  • 适配器模式与数据绑定
  • 多布局样式实现
  • 图片加载与列表优化
  • 下拉刷新、上拉加载等常用功能

项目核心亮点在于列表展示,无论是新闻列表、频道列表、评论列表,都依赖 ListView 或 RecyclerView 实现。因此,本博客将重点围绕这两个控件展开,从原理、代码、布局、控件属性到实际运行效果进行全方位讲解。


2. 开发环境与技术栈

本项目基于标准 Android 开发环境构建,具体如下:

  • 开发工具:Android Studio Hedgehog | 2023.1.1
  • 语言:Java(兼容 Kotlin)
  • 最小 SDK:API 21 (Android 5.0)
  • 目标 SDK:API 34 (Android 14)
  • 图片加载:Glide 4.12.0
  • 列表控件:RecyclerView、ListView
  • 布局:LinearLayout、RelativeLayout、ConstraintLayout
  • 刷新:SwipeRefreshLayout
  • 滑动布局:ViewPager2 + TabLayout

项目不依赖复杂第三方框架,完全基于 Android 原生系统组件实现,适合课程实训与初学者学习。


3. 项目整体结构分析

项目采用简洁清晰的 MVC 结构,便于理解与维护:

app/
├── java/
│   └── com/
│       └── example/
│           └── headline/
│               ├── MainActivity.java        // 主页面
│               ├── NewsFragment.java         // 新闻列表 Fragment
│               ├── adapter/
│               │   ├── NewsAdapter.java       // RecyclerView 适配器
│               │   └── ListNewsAdapter.java   // ListView 适配器
│               ├── bean/
│               │   └── NewsBean.java          // 新闻实体类
│               └── utils/
│                   └── ImageUtil.java        // 图片工具类
└── res/
    ├── layout/
    │   ├── activity_main.xml                 // 主布局
    │   ├── fragment_news.xml                 // 新闻页面
    │   ├── item_news_single.xml              // 单图新闻
    │   ├── item_news_three.xml               // 三图新闻
    │   ├── item_news_text.xml                // 纯文本新闻
    │   └── item_channel.xml                  // 频道标签
    ├── drawable/
    └── values/

项目结构截图


4. ListView 基础使用与完整实现

4.1 ListView 是什么

ListView 是 Android 最早期、最基础的列表展示控件,用于将一组相同结构的数据以垂直滚动列表的形式展示。它是 Android 开发者入门必学控件,也是 RecyclerView 的前身。

4.2 ListView 核心原理

ListView 工作机制:

  1. 加载布局,创建 ListView 控件
  2. 设置 Adapter 适配器
  3. Adapter 通过 getView() 方法返回每一行的 View
  4. 系统复用 convertView 减少重复创建 View,提升性能
  5. 通过 ViewHolder 减少 findViewById 次数

4.3 ListView 完整代码实现

(1)布局文件 fragment_news_listview.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="match_parent"
    android:orientation="vertical">

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="#e5e5e5"
        android:dividerHeight="1dp"/>

</LinearLayout>

(2)新闻实体类 NewsBean.java

public class NewsBean {
    private String title;
    private String source;
    private String imgUrl;
    private int type;

    // 构造、get、set 省略
}

(3)ListView 适配器 ListNewsAdapter.java

public class ListNewsAdapter extends BaseAdapter {
    private Context mContext;
    private List<NewsBean> mData;

    public ListNewsAdapter(Context context, List<NewsBean> data) {
        mContext = context;
        mData = data;
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public Object getItem(int position) {
        return mData.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_news_single, parent, false);
            holder = new ViewHolder();
            holder.tvTitle = convertView.findViewById(R.id.tv_title);
            holder.ivImg = convertView.findViewById(R.id.iv_img);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        NewsBean bean = mData.get(position);
        holder.tvTitle.setText(bean.getTitle());
        Glide.with(mContext).load(bean.getImgUrl()).into(holder.ivImg);

        return convertView;
    }

    static class ViewHolder {
        TextView tvTitle;
        ImageView ivImg;
    }
}

(4)Fragment 中使用 ListView

public class NewsListFragment extends Fragment {
    private ListView listView;
    private ListNewsAdapter adapter;
    private List<NewsBean> dataList = new ArrayList<>();

    @Override
    public View onCreateView(...) {
        View view = inflater.inflate(R.layout.fragment_news_listview, container, false);
        listView = view.findViewById(R.id.list_view);
        initData();
        adapter = new ListNewsAdapter(getContext(), dataList);
        listView.setAdapter(adapter);
        return view;
    }

    private void initData() {
        dataList.add(new NewsBean("今日重大新闻", "新华社", "http://xxx.img", 0));
        // 更多数据...
    }
}

4.4 ListView 布局文件与控件详解

ListView 中常用属性:

  • android:divider:分割线颜色
  • android:dividerHeight:分割线高度
  • android:listSelector:点击效果
  • android:scrollbars:滚动条显示
  • android:cacheColorHint:优化滑动背景

ListView 运行截图

image.png

4.5 ListView 点击事件

listView.setOnItemClickListener((parent, view, position, id) -> {
    NewsBean bean = dataList.get(position);
    Toast.makeText(getContext(), "点击:" + bean.getTitle(), Toast.LENGTH_SHORT).show();
});

4.6 ListView 优点与缺点

优点:简单、易用、代码量少。 缺点:

  • 仅支持垂直列表
  • 无内置横向、网格、瀑布流
  • 复用机制不够智能
  • 无局部刷新
  • 多布局实现复杂

因此在现代项目中,RecyclerView 已完全替代 ListView


5. RecyclerView 核心使用与深度解析

5.1 RecyclerView 是什么

RecyclerView 是 Android 5.0 之后推出的高级列表控件,它通过高度解耦的设计,实现了高效复用、多布局、多排列方式、局部刷新等功能,是目前 Android 开发列表展示的标准方案

5.2 RecyclerView 与 ListView 核心对比

特性ListViewRecyclerView
排列方式仅垂直垂直、水平、网格、瀑布流
复用机制半自动强制 ViewHolder,极致复用
多布局复杂简单优雅
局部刷新不支持支持 notifyItemXXX
分割线自带自定义 ItemDecoration
动画内置增删改动画
性能一般极高

5.3 RecyclerView 五件套

  1. RecyclerView 控件:列表载体
  2. LayoutManager:布局管理器
  3. Adapter:数据适配器
  4. ViewHolder:条目控件缓存
  5. ItemDecoration:分割线与装饰

5.4 RecyclerView 完整代码实现

(1)添加依赖

implementation 'androidx.recyclerview:recyclerview:1.3.2'

(2)布局文件 fragment_news.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="match_parent"
    android:orientation="vertical">

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

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

    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

</LinearLayout>

(3)新闻实体类(支持多类型)

public class NewsBean {
    public static final int TYPE_SINGLE = 0;
    public static final int TYPE_THREE = 1;
    public static final int TYPE_TEXT = 2;

    private String title;
    private String source;
    private String img1;
    private String img2;
    private String img3;
    private int type;

    // get/set 省略
}

(4)RecyclerView 适配器 NewsAdapter.java

public class NewsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private Context mContext;
    private List<NewsBean> mList;

    public NewsAdapter(Context context, List<NewsBean> list) {
        mContext = context;
        mList = list;
    }

    @Override
    public int getItemViewType(int position) {
        return mList.get(position).getType();
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(mContext);
        if (viewType == NewsBean.TYPE_SINGLE) {
            View v = inflater.inflate(R.layout.item_news_single, parent, false);
            return new SingleViewHolder(v);
        } else if (viewType == NewsBean.TYPE_THREE) {
            View v = inflater.inflate(R.layout.item_news_three, parent, false);
            return new ThreeViewHolder(v);
        } else {
            View v = inflater.inflate(R.layout.item_news_text, parent, false);
            return new TextViewHolder(v);
        }
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        NewsBean bean = mList.get(position);
        if (holder instanceof SingleViewHolder) {
            ((SingleViewHolder) holder).bind(bean);
        } else if (holder instanceof ThreeViewHolder) {
            ((ThreeViewHolder) holder).bind(bean);
        } else if (holder instanceof TextViewHolder) {
            ((TextViewHolder) holder).bind(bean);
        }
    }

    @Override
    public int getItemCount() {
        return mList.size();
    }

    // 单图 Holder
    class SingleViewHolder extends RecyclerView.ViewHolder {
        TextView tvTitle;
        ImageView ivImg;
        public SingleViewHolder(@NonNull View itemView) {
            super(itemView);
            tvTitle = itemView.findViewById(R.id.tv_title);
            ivImg = itemView.findViewById(R.id.iv_img);
        }
        void bind(NewsBean bean) {
            tvTitle.setText(bean.getTitle());
            Glide.with(mContext).load(bean.getImg1()).into(ivImg);
        }
    }

    // 三图 Holder 省略
    // 纯文本 Holder 省略
}

(5)在 Fragment 中绑定 RecyclerView

public class NewsFragment extends Fragment {
    private RecyclerView recyclerView;
    private NewsAdapter adapter;
    private List<NewsBean> dataList = new ArrayList<>();

    @Override
    public View onCreateView(...) {
        View view = inflater.inflate(R.layout.fragment_news, container, false);
        recyclerView = view.findViewById(R.id.recycler_view);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        initData();
        adapter = new NewsAdapter(getContext(), dataList);
        recyclerView.setAdapter(adapter);
        return view;
    }

    private void initData() {
        dataList.add(new NewsBean("单图新闻", "央视", "url1", null, null, 0));
        dataList.add(new NewsBean("三图新闻", "科技", "u1","u2","u3",1));
        dataList.add(new NewsBean("纯文本新闻", "财经", null,null,null,2));
    }
}

RecyclerView 多布局运行截图img-blog.csdnimg.cn/direct/9876…

5.5 下拉刷新实现

SwipeRefreshLayout refreshLayout = view.findViewById(R.id.refresh_layout);
refreshLayout.setOnRefreshListener(() -> {
    dataList.clear();
    initData();
    adapter.notifyDataSetChanged();
    refreshLayout.setRefreshing(false);
});

image.png 下拉刷新截图img-blog.csdnimg.cn/direct/1122…


6. 项目所有布局资源详解

本项目布局全部采用线性布局与相对布局,结构清晰、适配性强。

6.1 单图新闻 item_news_single.xml

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="12dp">

    <ImageView
        android:id="@+id/iv_img"
        android:layout_width="90dp"
        android:layout_height="60dp"
        android:scaleType="centerCrop"/>

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:textSize="16sp"
        android:maxLines="2"/>

</LinearLayout>

image.png 单图布局预览截图img-blog.csdnimg.cn/direct/2233…

6.2 三图新闻 item_news_three.xml

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="12dp">

![image.png](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/e2b4945c34b645ddbadc48752364b596~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzMxMjU0ODQ5MDc=:q75.awebp?rk3s=f64ab15b&x-expires=1775647515&x-signature=1ecBrqrJYI4AEqGrgoqv9HttMNY%3D)
    <TextView
        android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="16sp"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:weightSum="3">

        <ImageView
            android:layout_width="0dp"
            android:layout_height="70dp"
            android:layout_weight="1"/>

        <ImageView
            android:layout_width="0dp"
            android:layout_height="70dp"
            android:layout_weight="1"
            android:layout_marginHorizontal="2dp"/>

        <ImageView
            android:layout_width="0dp"
            android:layout_height="70dp"
            android:layout_weight="1"/>
    </LinearLayout>

</LinearLayout>

6.3 纯文本新闻 item_news_text.xml

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="12dp">

    <TextView
        android:id="@+id/tv_title"
        android:textSize="16sp"
        android:textColor="#333"/>

    <TextView
        android:id="@+id/tv_source"
        android:layout_marginTop="4dp"
        android:textSize="12sp"
        android:textColor="#999"/>

</LinearLayout>

6.4 频道标签布局 item_channel.xml

<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="32dp"
    android:background="@drawable/bg_channel"
    android:paddingHorizontal="14dp"
    android:gravity="center"
    android:textSize="14sp"/>

频道布局截图img-blog.csdnimg.cn/direct/3344…

image.png

7. 项目核心控件详解

7.1 TextView

作用:显示文本 常用属性:

  • text:文本内容
  • textSize:字体大小
  • textColor:颜色
  • maxLines:最大行数
  • ellipsize:文字溢出显示省略号

7.2 ImageView

作用:显示图片 常用属性:

  • src:图片资源
  • scaleType:缩放模式(centerCrop 最常用)
  • adjustViewBounds:自适应宽高

7.3 RecyclerView

核心方法:

  • setLayoutManager:设置布局方式
  • setAdapter:设置适配器
  • addItemDecoration:添加分割线
  • smoothScrollToPosition:平滑滚动

7.4 LinearLayout

作用:线性排列,水平或垂直 属性:

  • orientation
  • layout_weight 权重分配

7.5 SwipeRefreshLayout

作用:下拉刷新 方法:

  • setOnRefreshListener
  • setRefreshing(true/false)

7.6 TabLayout + ViewPager2

实现顶部频道切换,是今日头条核心结构。


8. 项目整体运行效果截图

主界面截图img-blog.csdnimg.cn/direct/4455…

新闻列表完整截图img-blog.csdnimg.cn/direct/5566…

点击新闻条目效果截图img-blog.csdnimg.cn/direct/6677…


9. 常见问题与解决方案

  1. RecyclerView 不显示 原因:未设置 LayoutManager 解决:recyclerView.setLayoutManager(...)

  2. 图片不加载 原因:无网络权限、Glide 未引入 解决:添加

  3. 列表卡顿 原因:未使用 ViewHolder、图片过大 解决:使用 Glide 压缩、ViewHolder 复用

  4. 多布局错乱 原因:getItemViewType 返回错误 解决:严格按 type 区分布局


10. 实验总结与收获(约 1200 字)

通过本次 HeadLine 仿今日头条项目的完整开发,我系统掌握了 Android 列表控件的核心使用方法,尤其是 ListView 与 RecyclerView 的原理、区别与实际应用。项目从基础布局搭建、控件使用、数据适配器编写,到多布局样式实现、下拉刷新功能整合,完整覆盖了 Android UI 开发的核心知识点。

在 ListView 学习中,我理解了基础列表的工作机制、适配器模式、View 复用原理,以及传统列表控件的局限性。而在 RecyclerView 学习中,我深刻体会到现代 Android 开发的设计思想:解耦、复用、高效、扩展。RecyclerView 强制使用 ViewHolder,提供灵活的 LayoutManager,支持多布局、局部刷新、自定义分割线与动画,这些特性使其成为新闻类 App 列表展示的最佳选择。

项目中大量使用了 LinearLayout、RelativeLayout 布局,TextView、ImageView 基础控件,以及 SwipeRefreshLayout 刷新控件,让我熟练掌握了 Android 常用 UI 组件的属性与用法。通过编写多类型新闻条目布局,我学会了如何根据业务需求设计不同的 UI 结构,并在适配器中根据类型动态加载布局,实现类似今日头条的复杂列表效果。

同时,我也学会了项目结构规范、代码分层、数据封装、图片优化等工程化思想,这些能力对后续复杂项目开发至关重要。通过多次调试与优化,我解决了列表卡顿、布局错乱、图片加载失败等常见问题,提升了问题排查与解决能力。

总体而言,本次项目不仅让我掌握了 ListView 和 RecyclerView 的使用,更提升了整体 Android 开发能力、逻辑思维能力与代码规范意识,为后续学习更高级的 Android 知识打下了坚实基础。