HeadLine仿今日头条项目

0 阅读16分钟

HeadLine仿今日头条项目

一、项目概述

1.1项目背景

在移动应用开发中,列表展示是最常见的需求之一。无论是社交应用的时间线、电商应用的商品列表,还是新闻应用的资讯流,都离不开高效的列表实现。本项目《仿今日头条》是一个典型的新闻资讯类应用,通过实现一个包含多种卡片类型的新闻列表,展示了 Android 平台高级列表开发的最佳实践。

1.2项目整体架构

仿今日头条项目:
1、MainActivity.java 主活动,数据初始化和列表配置
2、NewsAdapter.java RecyclerView适配器
3、NewsBean.java 数据模型
4、activity_main.xml 主界面布局
5、list_item_one.xml 单图新闻布局
6、list_item_two.xml 三图新闻布局
7、title_bar.xml 标题栏布局

二、RecyclerView核心概念详解

2.1 RecyclerView的工作机制

RecyclerView 的工作机制可以概括为"创建-复用-绑定"三部曲:
用户滑动列表

RecyclerView 检测到需要显示新条目

调用 Adapter.onCreateViewHolder() 创建新视图

调用 Adapter.onBindViewHolder() 绑定数据

条目滑出屏幕时,视图进入回收池

新条目需要显示时,从回收池复用视图

2.2核心组件说明
2.2.1 LayoutManager(布局管理器)

LayoutManager 负责决定条目如何排列和显示。本项目使用LinearLayoutManager实现垂直列表: image.png LinearLayoutManager 内部维护了条目位置的缓存,能够高效地计算哪些条目应该显示在屏幕上。

2.2.2 Adapter(适配器)

适配器是 RecyclerView 和数据之间的桥梁,本项目的 NewsAdapter 继承自 RecyclerView.Adapter <RecyclerView.ViewHolder>:

public class NewsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    // 三个必须重写的方法
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // 根据视图类型创建不同的 ViewHolder
    }
    
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        // 将数据绑定到 ViewHolder
    }
    
    @Override
    public int getItemCount() {
        // 返回数据总数
        return NewsList.size();
    }
}
2.2.3 ViewHolder(视图持有者)

ViewHolder是RecyclerView性能优化的核心。它缓存了子视图的引用,避免了重复的findViewById()调用:

image.png

2.3视图类型机制

RecyclerView 支持多种视图类型,这是通过getItemViewType方法实现的:

@Override
public int getItemViewType(int position) {
    //返回当前位置的视图类型
    return NewsList.get(position).getType();
}

本项目中,getType() 返回的值决定了使用哪种布局:
type = 1:使用 list_item_one.xml(单图新闻)
type = 2:使用 list_item_two.xml(三图新闻)

三、项目数据模型设计

3.1 NewsBean 类详解

NewsBean是新闻的数据模型,定义了新闻包含的所有属性:

public class NewsBean {
    private int id;                   //新闻id
    private String title;            //新闻标题
    private List<Integer> imgList; //新闻图片
    private String name;             //用户名
    private String comment;         //用户评论
    private String time;             //新闻发布时间
    private int type;                 //新闻类型
    // Getter 和 Setter 方法
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    
    //其他 getter/setter
3.2使用List存储图片的优势
    private List<Integer> imgList;  // 使用 List 存储图片资源ID

这种设计非常灵活:
单图新闻:imgList.size() == 1
三图新闻:imgList.size() == 3
置顶新闻:imgList.size() == 0 //无图片
如果未来需要支持两图、四图等布局,只需要添加对应的布局文件和判断逻辑即可。

3.3数据初始化流程

在MainActivity.setData()方法中,创建了6条新闻数据:

private void setData() {
    //数组组装逻辑  为每条新闻创建 NewsBean 对象
    //根据不同的位置(0-5)设置不同的图片列表
    NewsList = new ArrayList<NewsBean>();
    NewsBean bean;
    for (int i = 0; i < titles.length; i++) {
        bean = new NewsBean();
        bean.setId(i + 1);
        bean.setTitle(titles[i]);
        bean.setName(names[i]);
        bean.setComment(comments[i]);
        bean.setTime(times[i]);
        bean.setType(types[i]);
        switch (i) {
            case 0: //置顶新闻的图片设置
                List<Integer> imgList0 = new ArrayList<>();
                bean.setImgList(imgList0);
                break;
            case 1://设置第2个条目的图片数据
                List<Integer> imgList1 = new ArrayList<>();
                imgList1.add(icons1[i - 1]);
                bean.setImgList(imgList1);
                break;
            case 2://设置第3个条目的图片数据
                List<Integer> imgList2 = new ArrayList<>();
                imgList2.add(icons2[i - 2]);
                imgList2.add(icons2[i - 1]);
                imgList2.add(icons2[i]);
                bean.setImgList(imgList2);
                break;
            case 3://设置第4个条目的图片数据
                List<Integer> imgList3 = new ArrayList<>();
                imgList3.add(icons1[i - 2]);
                bean.setImgList(imgList3);
                break;
            case 4://设置第5个条目的图片数据
                List<Integer> imgList4 = new ArrayList<>();
                imgList4.add(icons2[i - 1]);
                imgList4.add(icons2[i]);
                imgList4.add(icons2[i + 1]);
                bean.setImgList(imgList4);
                break;
            case 5://设置第6个条目的图片数据
                List<Integer> imgList5 = new ArrayList<>();
                imgList5.add(icons1[i - 3]);
                bean.setImgList(imgList5);
                break;
        }
        NewsList.add(bean);
    }

四、多视图类型适配器实现

4.1 NewsAdapter 完整代码分析

image.png

image.png

image.png
视图绑定逻辑: image.png

image.png

image.png

4.2视图类型判断的技巧

在 onBindViewHolder 中使用 instanceof 判断 ViewHolder 类型:

    if (holder instanceof MyViewHolder1) {
    // 处理单图视图
    } else if (holder instanceof MyViewHolder2) {
    // 处理三图视图
    }
4.3置顶标识的特殊处理
    if (position == 0) {
    holder.iv_top.setVisibility(View.VISIBLE);  // 显示"置顶"图标
    holder.iv_img.setVisibility(View.GONE);     // 置顶新闻没有图片
} else {
    holder.iv_top.setVisibility(View.GONE);     // 其他新闻不显示置顶
    holder.iv_img.setVisibility(View.VISIBLE);  // 显示右侧图片
}

五、布局资源文件深度剖析

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/light_gray_color"
    android:orientation="vertical">
    <!-- 包含标题栏 -->
    <include layout="@layout/title_bar" />
    <!-- 频道标签栏 -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="@android:color/white"
        android:orientation="horizontal">
        <TextView
            style="@style/tvStyle"
            android:text="推荐"
            android:textColor="@android:color/holo_red_dark" />
        <TextView
            style="@style/tvStyle"
            android:text="抗疫"
            android:textColor="@color/gray_color" />
        <TextView
            style="@style/tvStyle"
            android:text="小视频"
            android:textColor="@color/gray_color" />
        <TextView
            style="@style/tvStyle"
            android:text="北京"
            android:textColor="@color/gray_color" />
        <TextView
            style="@style/tvStyle"
            android:text="视频"
            android:textColor="@color/gray_color" />
        <TextView
            style="@style/tvStyle"
            android:text="热点"
            android:textColor="@color/gray_color" />
        <TextView
            style="@style/tvStyle"
            android:text="娱乐"
            android:textColor="@color/gray_color" />
    </LinearLayout>
    <!-- 分割线 -->
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#eeeeee" />
    <!-- RecyclerView 列表 -->
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

布局解析:
1.使用 LinearLayout 垂直排列所有元素
2.include 标签用于复用标题栏布局
3.频道标签栏使用水平 LinearLayout 实现
4.1dp 高的 View 作为分割线
5.RecyclerView 占据剩余空间(layout_height="match_parent")

5.2 title_bar.xml 标题栏布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="#d33d3c"
    android:orientation="horizontal"
    android:paddingLeft="10dp"
    android:paddingRight="10dp">
<!--    标题栏-->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="仿今日头条"
        android:textColor="@android:color/white"
        android:textSize="22sp" />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="35dp"
        android:layout_gravity="center_vertical"
        android:layout_marginStart="15dp"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="15dp"
        android:background="@drawable/search_bg"
        android:gravity="center_vertical"
        android:textColor="@android:color/black"
        android:hint="搜你想搜的"
        android:textColorHint="@color/gray_color"
        android:textSize="14sp"
        android:paddingLeft="30dp" />
</LinearLayout>

设计特点:
1.高度 50dp,红色背景(#d33d3c)
2.左侧显示"仿今日头条"标题,白色文字,22sp
3.右侧搜索框带搜索图标背景(通过 android:background="@drawable/search_bg" 实现)
4.搜索框提示文字"搜你想搜的"

5.3 list_item_one.xml - 单图新闻布局
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="90dp"
    android:layout_marginBottom="8dp"
    android:background="@android:color/white"
    android:padding="8dp">
    <LinearLayout
        android:id="@+id/ll_info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:id="@+id/tv_title"
            android:layout_width="280dp"
            android:layout_height="wrap_content"
            android:maxLines="2"
            android:textColor="#3c3c3c"
            android:textSize="16sp" />
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <ImageView
                android:id="@+id/iv_top"
                android:layout_width="20dp"
                android:layout_height="20dp"
                android:layout_alignParentBottom="true"
                android:src="@drawable/top" />
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_toRightOf="@id/iv_top"
                android:orientation="horizontal">
                <TextView
                    android:id="@+id/tv_name"
                    style="@style/tvInfo" />
                <TextView
                    android:id="@+id/tv_comment"
                    style="@style/tvInfo" />
                <TextView
                    android:id="@+id/tv_time"
                    style="@style/tvInfo" />
            </LinearLayout>
        </RelativeLayout>
    </LinearLayout>
    <ImageView
        android:id="@+id/iv_img"
        android:layout_width="match_parent"
        android:layout_height="90dp"
        android:layout_toRightOf="@id/ll_info"
        android:padding="3dp" />
</RelativeLayout>

布局详解:
1.外层 RelativeLayout: 高度固定 90dp
白色背景
底部外边距 8dp(与下一条新闻间距)
内边距 8dp
2.左侧信息区域:
使用 LinearLayout 垂直排列
宽度 280dp(固定宽度,为右侧图片留出空间)
3.标题 TextView:
maxLines="2":最多显示2行,超出自动截断
颜色 #3c3c3c,字号 16sp
4.底部信息栏:
包含置顶图标和作者/评论/时间信息
置顶图标默认隐藏(visibility="gone")
使用 layout_alignParentBottom="true" 将信息栏固定在底部
5.右侧图片:
layout_toRightOf="@id/ll_info":位于信息区域右侧
高度 90dp,宽度自适应(match_parent)
内边距 3dp,形成图片边框效果

5.4 list_item_two.xml - 三图新闻布局
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="8dp"
    android:background="@android:color/white">
    <TextView
        android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:maxLines="2"
        android:padding="8dp"
        android:textColor="#3c3c3c"
        android:textSize="16sp" />
    <LinearLayout
        android:id="@+id/ll_img"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/tv_title"
        android:orientation="horizontal">
        <ImageView
            android:id="@+id/iv_img1"
            style="@style/ivImg"/>
        <ImageView
            android:id="@+id/iv_img2"
            style="@style/ivImg"/>
        <ImageView
            android:id="@+id/iv_img3"
            style="@style/ivImg"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/ll_img"
        android:orientation="vertical"
        android:padding="8dp">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <TextView
                android:id="@+id/tv_name"
                style="@style/tvInfo" />
            <TextView
                android:id="@+id/tv_comment"
                style="@style/tvInfo" />
            <TextView
                android:id="@+id/tv_time"
                style="@style/tvInfo" />
        </LinearLayout>
    </LinearLayout>
</RelativeLayout>

布局详解:
1.外层 RelativeLayout:
高度自适应(wrap_content)
白色背景,底部外边距 8dp
2.标题区域:
位于顶部,全宽
最多显示2行,内边距 8dp
3.图片区域:
位于标题下方(layout_below="@id/tv_title")
水平排列的三张图片
使用样式统一图片尺寸
4.底部信息:
位于图片区域下方
显示作者、评论数、时间

5.5 样式文件分析
    <!-- tvInfo 样式 - 用于底部信息文字 -->
<style name="tvInfo">
    <item name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:textSize">12sp</item>
    <item name="android:textColor">#9c9c9c</item>
    <item name="android:layout_marginRight">8dp</item>
</style>

<!-- ivImg 样式 - 用于三图新闻的图片 -->
<style name="ivImg">
    <item name="android:layout_width">0dp</item>
    <item name="android:layout_height">80dp</item>
    <item name="android:layout_weight">1</item>
    <item name="android:layout_margin">3dp</item>
    <item name="android:scaleType">centerCrop</item>
</style>

样式优势:
1.代码复用:多处使用相同属性时只需引用样式
2.易于维护:修改样式定义即可全局生效
3.布局清晰:减少布局文件中的重复代码

六、ViewHolder 模式与性能优化

6.1 ViewHolder 模式原理

ViewHolder 模式的核心思想是缓存视图引用。在传统的 ListView 中,getView() 方法会被频繁调用,如果每次都通过 findViewById() 查找控件,会造成严重的性能问题。

没有使用 ViewHolder 的代码:

    @Override
public View getView(int position, View convertView, ViewGroup parent) {
    convertView = inflater.inflate(R.layout.list_item, null);
    TextView title = convertView.findViewById(R.id.title);  // 每次都查找
    TextView content = convertView.findViewById(R.id.content); // 每次都查找
    title.setText(titles[position]);
    content.setText(contents[position]);
    return convertView;
}

使用 ViewHolder 的代码:

    @Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.list_item, null);
        holder = new ViewHolder();
        holder.title = convertView.findViewById(R.id.title);
        holder.content = convertView.findViewById(R.id.content);
        convertView.setTag(holder);  // 缓存 ViewHolder
    } else {
        holder = (ViewHolder) convertView.getTag();  // 复用 ViewHolder
    }
    holder.title.setText(titles[position]);
    holder.content.setText(contents[position]);
    return convertView;
}

static class ViewHolder {
    TextView title;
    TextView content;
}
6.2 RecyclerView 的强制 ViewHolder

RecyclerView 在设计上强制使用 ViewHolder 模式,无法绕过:

    // RecyclerView 要求必须继承 ViewHolder
class MyViewHolder extends RecyclerView.ViewHolder {
    TextView title;
    ImageView image;
    
    public MyViewHolder(View itemView) {
        super(itemView);
        title = itemView.findViewById(R.id.title);
        image = itemView.findViewById(R.id.image);
    }
}

这种设计保证了:
1.性能最优:不会出现忘记使用 ViewHolder 的情况
2.代码规范:统一的视图缓存机制
3.类型安全:泛型支持

6.3 视图复用机制详解

RecyclerView 的视图复用比 ListView 更加高效:

屏幕可见区域(显示5个条目)

用户向下滑动,第1个条目滑出屏幕

第1个条目的视图进入 RecyclerView 的回收池

用户继续滑动,需要显示第6个条目

RecyclerView 从回收池中取出第1个条目的视图 ↓
调用 onBindViewHolder() 更新数据

第6个条目显示,复用了第1个条目的视图

回收池层级:

  1. Scrap:临时分离的视图,用于布局过程
  2. Cache:缓存最近使用的视图,默认大小2
  3. RecycledViewPool:共享视图池,可以跨 RecyclerView 复用

七、数据绑定与界面更新机制

7.1数据绑定流程:

数据源更新 ↓
调用 notifyDataSetChanged() 或更细粒度的通知方法

RecyclerView 重新布局

Adapter 重新绑定可见区域的数据

界面更新完成

八、RecyclerView 在仿今日头条项目中的使用详解

8.2.1 RecyclerView 的初始化流程

第一步:在布局文件中定义 RecyclerView

位置:activity_main.xml

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

第二步:在 Activity 中初始化
位置:MainActivity.java 的 onCreate() 方法

mRecyclerView = findViewById(R.id.rv_list);  // 找到控件
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));  // 设置布局管理器
mAdapter = new NewsAdapter(MainActivity.this, NewsList);  // 创建适配器
mRecyclerView.setAdapter(mAdapter);  // 设置适配器

代码解析:

  • findViewById(R.id.rv_list):通过 ID 找到 RecyclerView 控件
  • setLayoutManager():设置布局管理器,这里使用 LinearLayoutManager 实现垂直列表
  • NewsAdapter:自定义适配器,负责创建视图和绑定数据
  • setAdapter():将适配器设置给 RecyclerView
8.2.2 多视图类型的实现机制

核心代码1:定义视图类型

// 在 NewsBean 中定义 type 字段
private int type;  // 1=单图新闻,2=三图新闻

核心代码2:返回视图类型

@Override
public int getItemViewType(int position) {
    return NewsList.get(position).getType();  // 根据数据返回类型
}

核心代码3:根据类型创建不同的视图

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (viewType == 1) {
        // 加载单图新闻布局
        View itemView = LayoutInflater.from(mContext)
            .inflate(R.layout.list_item_one, parent, false);
        return new MyViewHolder1(itemView);
    } else if (viewType == 2) {
        // 加载三图新闻布局
        View itemView = LayoutInflater.from(mContext)
            .inflate(R.layout.list_item_two, parent, false);
        return new MyViewHolder2(itemView);
    }
    return null;
}

核心代码4:分别绑定数据

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    NewsBean bean = NewsList.get(position);
    
    if (holder instanceof MyViewHolder1) {
        // 绑定单图新闻数据
        ((MyViewHolder1) holder).title.setText(bean.getTitle());
        ((MyViewHolder1) holder).name.setText(bean.getName());
        // ... 其他数据绑定
    } else if (holder instanceof MyViewHolder2) {
        // 绑定三图新闻数据
        ((MyViewHolder2) holder).title.setText(bean.getTitle());
        ((MyViewHolder2) holder).name.setText(bean.getName());
        // ... 其他数据绑定
    }
}
8.2.3 ViewHolder 的实现

单图新闻 ViewHolder:

class MyViewHolder1 extends RecyclerView.ViewHolder {
    // 声明控件
    ImageView iv_top, iv_img;
    TextView title, name, comment, time;
    
    public MyViewHolder1(View view) {
        super(view);
        // 在构造函数中查找并缓存控件
        iv_top = view.findViewById(R.id.iv_top);
        iv_img = view.findViewById(R.id.iv_img);
        title = view.findViewById(R.id.tv_title);
        name = view.findViewById(R.id.tv_name);
        comment = view.findViewById(R.id.tv_comment);
        time = view.findViewById(R.id.tv_time);
    }
}

三图新闻 ViewHolder:

class MyViewHolder2 extends RecyclerView.ViewHolder {
    // 声明控件
    ImageView iv_img1, iv_img2, iv_img3;
    TextView title, name, comment, time;
    
    public MyViewHolder2(View view) {
        super(view);
        // 在构造函数中查找并缓存控件
        iv_img1 = view.findViewById(R.id.iv_img1);
        iv_img2 = view.findViewById(R.id.iv_img2);
        iv_img3 = view.findViewById(R.id.iv_img3);
        title = view.findViewById(R.id.tv_title);
        name = view.findViewById(R.id.tv_name);
        comment = view.findViewById(R.id.tv_comment);
        time = view.findViewById(R.id.tv_time);
    }
}

九、控件使用总结

9.1 项目中使用的所有控件
9.1.1 RecyclerView(1个)

作用:  新闻列表展示控件,是整个项目的核心列表控件

使用位置:  activity_main.xml

关键属性:

  • android:id="@+id/rv_list":控件唯一标识
  • android:layout_width="match_parent":宽度填满父容器
  • android:layout_height="match_parent":高度填满父容器

代码示例:

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rv_list"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
9.1.2 LinearLayout(6个)

作用:  线性布局容器,用于垂直或水平排列子控件

使用位置:

  • activity_main.xml:外层容器(垂直排列)、频道标签栏(水平排列)
  • title_bar.xml:标题栏容器(水平排列)
  • list_item_one.xml:左侧信息区域(垂直排列)、底部信息栏(水平排列)
  • list_item_two.xml:图片容器(水平排列)、底部信息容器(水平排列)

关键属性:

  • android:orientation="vertical":子控件垂直排列
  • android:orientation="horizontal":子控件水平排列
  • android:layout_width:宽度
  • android:layout_height:高度

代码示例:

<!-- 垂直排列 -->
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
    <TextView ... />
    <ImageView ... />
    
</LinearLayout>

<!-- 水平排列 -->
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    
    <TextView ... />
    <TextView ... />
    
</LinearLayout>
9.1.3 RelativeLayout(3个)

作用:  相对布局容器,子控件可以相对于父容器或其他控件定位

使用位置:

  • list_item_one.xml:整个条目的外层容器
  • list_item_one.xml:底部信息栏的内层容器
  • list_item_two.xml:整个条目的外层容器

关键属性:

  • android:layout_below="@id/xxx":位于指定控件下方
  • android:layout_toRightOf="@id/xxx":位于指定控件右侧
  • android:layout_alignParentBottom="true":对齐父容器底部
  • android:layout_centerVertical="true":垂直居中

代码示例:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    
    <TextView
        android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    
    <ImageView
        android:id="@+id/iv_img"
        android:layout_width="100dp"
        android:layout_height="80dp"
        android:layout_below="@id/tv_title"
        android:layout_toRightOf="@id/tv_title" />
        
</RelativeLayout>
9.1.4 TextView(多个)

作用:  显示文字内容,包括新闻标题、作者名、评论数、发布时间

使用位置:

  • activity_main.xml:频道标签(推荐、抗疫、小视频等)
  • list_item_one.xml:标题、作者、评论、时间
  • list_item_two.xml:标题、作者、评论、时间
  • title_bar.xml:标题栏文字

关键属性:

  • android:text:显示的文本内容
  • android:textSize:文字大小(sp单位)
  • android:textColor:文字颜色
  • android:maxLines:最大行数
  • android:ellipsize:超出时省略号位置
  • android:gravity:文字对齐方式

代码示例:

<!-- 标题 TextView -->
<TextView
    android:id="@+id/tv_title"
    android:layout_width="280dp"
    android:layout_height="wrap_content"
    android:maxLines="2"
    android:textSize="16sp"
    android:textColor="#3c3c3c"
    android:text="各地餐企齐行动,杜绝餐饮浪费" />

<!-- 作者 TextView(使用样式) -->
<TextView
    android:id="@+id/tv_name"
    style="@style/tvInfo"
    android:text="央视新闻客户端" />

<!-- 评论数 TextView -->
<TextView
    android:id="@+id/tv_comment"
    style="@style/tvInfo"
    android:text="9884评" />

<!-- 时间 TextView -->
<TextView
    android:id="@+id/tv_time"
    style="@style/tvInfo"
    android:text="6小时前" />
9.1.5 ImageView(多个)

作用:  显示图片,包括新闻图片和置顶图标

使用位置:

  • list_item_one.xml:右侧新闻图片、置顶图标
  • list_item_two.xml:三张新闻图片

关键属性:

  • android:src:图片资源(如 @drawable/top

  • android:scaleType:图片缩放类型

    • centerCrop:居中裁剪,填满控件
    • fitCenter:居中显示,保持比例
    • fitXY:拉伸填满
  • android:visibility:可见性(visible/gone/invisible

代码示例:

<!-- 置顶图标 -->
<ImageView
    android:id="@+id/iv_top"
    android:layout_width="20dp"
    android:layout_height="20dp"
    android:src="@drawable/top"
    android:visibility="gone" />

<!-- 右侧新闻图片 -->
<ImageView
    android:id="@+id/iv_img"
    android:layout_width="match_parent"
    android:layout_height="90dp"
    android:padding="3dp"
    android:scaleType="centerCrop" />

<!-- 三图新闻图片(使用样式) -->
<ImageView
    android:id="@+id/iv_img1"
    style="@style/ivImg"
    android:scaleType="centerCrop" />

9.1.6 EditText(1个)

作用:  搜索输入框,接收用户输入的关键字

使用位置:  title_bar.xml

关键属性:

  • android:hint:输入提示文字("搜你想搜的")
  • android:textColorHint:提示文字颜色
  • android:background:背景(搜索框背景样式)
  • android:paddingLeft:左内边距(为搜索图标留出空间)
  • android:gravity="center_vertical":垂直居中

代码示例:

<EditText
    android:layout_width="match_parent"
    android:layout_height="35dp"
    android:layout_gravity="center_vertical"
    android:hint="搜你想搜的"
    android:textColorHint="@color/gray_color"
    android:background="@drawable/search_bg"
    android:paddingLeft="30dp"
    android:textSize="14sp"
    android:gravity="center_vertical" />

9.1.7 View(1个)

作用:  作为分割线,分隔频道标签栏和新闻列表

使用位置:  activity_main.xml

关键属性:

  • android:layout_width="match_parent":宽度填满
  • android:layout_height="1dp":高度1像素
  • android:background="#eeeeee":浅灰色背景

代码示例:

<View
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="#eeeeee" />

9.1.8 include(1个)

作用:  引入其他布局文件,实现布局复用

使用位置:  activity_main.xml

关键属性:

  • layout="@layout/title_bar":指定要引入的布局文件

代码示例:

<!-- 引入标题栏布局 -->
<include layout="@layout/title_bar" />

优势:

  • 代码复用:标题栏只需定义一次,多处使用
  • 易于维护:修改标题栏只需改一个文件
  • 结构清晰:主布局文件更简洁

十、总结

10.1项目执行结果:

HeadLine:
image.png

ListView:
image.png
RecyclerView:

image.png

10.2项目核心内容回顾:
1. RecyclerView 的使用
  • 初始化findViewById() → setLayoutManager() → setAdapter()
  • 适配器:必须实现 onCreateViewHolder()onBindViewHolder()getItemCount() 三个方法
  • 多视图类型:通过 getItemViewType() 返回不同类型,在 onCreateViewHolder() 中创建不同布局
2. 布局资源
  • activity_main.xml:主布局,包含标题栏、频道标签、RecyclerView
  • title_bar.xml:标题栏布局,包含标题文字和搜索框
  • list_item_one.xml:单图新闻布局,左侧文字+右侧图片
  • list_item_two.xml:三图新闻布局,标题+三张图片+底部信息
3. 核心控件
  • RecyclerView:列表控件
  • TextView:显示文字(标题、作者、评论、时间)
  • ImageView:显示图片(新闻图、置顶图标)
  • LinearLayout:垂直或水平排列控件
  • RelativeLayout:相对位置定位