[HarmonyOS NEXT 实战案例:新闻阅读应用] 基础篇 - 水平分割布局构建新闻阅读界面

2025-06-09 23:14:55
115次阅读
0个评论

[HarmonyOS NEXT 实战案例:新闻阅读应用] 基础篇 - 水平分割布局构建新闻阅读界面

项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star

效果演示

image.png

引言

新闻阅读应用是移动应用开发中的常见场景,用户通过这类应用获取最新资讯和内容。一个设计良好的新闻阅读界面需要清晰展示新闻分类和新闻列表,方便用户快速浏览和选择感兴趣的内容。本教程将详细讲解如何使用HarmonyOS NEXT的RowSplit组件构建一个新闻阅读应用界面,通过水平分割布局将界面分为新闻分类标签和新闻列表区域。

组件概述

在本案例中,我们将使用以下HarmonyOS NEXT组件:

组件名称 功能描述
RowSplit 水平分割布局容器,将界面分为左右两部分
Column 垂直布局容器,用于垂直排列子组件
List 列表容器,用于显示新闻列表
ListItem 列表项组件,用于显示单条新闻
Row 水平布局容器,用于水平排列子组件
Text 文本组件,用于显示新闻标题、内容等
Image 图片组件,用于显示新闻缩略图
Button 按钮组件,用于新闻分类标签
ForEach 循环渲染组件,用于渲染新闻分类和新闻列表

数据模型

在实现界面之前,我们首先定义新闻数据的模型:

class NewsItem {
  title: string;
  source: string;
  time: string;
  imageUrl: Resource;
  category: string;

  constructor(title: string, source: string, time: string, imageUrl: Resource, category: string) {
    this.title = title;
    this.source = source;
    this.time = time;
    this.imageUrl = imageUrl;
    this.category = category;
  }
}

这个模型包含新闻的标题、来源、时间、图片和分类信息。

代码实现

组件结构

首先,我们定义了一个名为NewsReaderExample的自定义组件,并在其中定义了新闻分类和新闻数据:

@Component
export struct NewsReaderExample {
  @State selectedCategory: string = '推荐';
  private categories: string[] = ['推荐', '科技', '体育', '财经', '娱乐', '健康'];
  @State newsData: NewsItem[] = [
    new NewsItem('HarmonyOS NEXT发布,带来全新的分布式体验', '科技日报', '10分钟前', $r('app.media.big30'), '科技'),
    new NewsItem('全国科技创新大会在北京召开', '新闻网', '30分钟前', $r('app.media.big31'), '科技'),
    new NewsItem('2023年全球智能手机市场分析报告', '科技评论', '1小时前', $r('app.media.big32'), '科技'),
    new NewsItem('国足最新一期集训名单公布', '体育新闻', '2小时前', $r('app.media.big33'), '体育'),
    new NewsItem('NBA季后赛最新战报', '体育周刊', '3小时前', $r('app.media.big34'), '体育'),
    new NewsItem('央行发布最新货币政策报告', '财经日报', '4小时前', $r('app.media.big35'), '财经'),
    new NewsItem('A股市场今日行情分析', '证券时报', '5小时前', $r('app.media.big36'), '财经'),
    new NewsItem('某流量明星最新电影票房破10亿', '娱乐周刊', '6小时前', $r('app.media.big37'), '娱乐'),
    new NewsItem('夏季养生指南:如何科学防暑', '健康时报', '7小时前', $r('app.media.big38'), '健康')
  ];

  build() {
    // 组件内容
  }
}

在这个组件中:

  1. selectedCategory状态变量用于跟踪当前选中的新闻分类
  2. categories数组包含所有可用的新闻分类
  3. newsData状态变量包含所有新闻数据

外层容器

我们使用Column组件作为最外层容器,包含标题文本和主要内容区域:

Column() {
  Text('新闻阅读应用布局')
    .fontSize(20)
    .fontWeight(FontWeight.Bold)
    .margin({ bottom: 10 })

  RowSplit() {
    // RowSplit内容
  }
  .height(600)
}
.width('100%')
.padding(15)

外层Column设置了宽度为100%和15的内边距,确保整个界面充分利用可用空间并与屏幕边缘有适当的间距。

水平分割布局

我们使用RowSplit组件将界面分为左右两部分:

RowSplit() {
  // 左侧新闻分类区域
  Column() {
    // 新闻分类内容
  }
  .width('25%')
  .backgroundColor('#f5f5f5')

  // 右侧新闻列表区域
  Column() {
    // 新闻列表内容
  }
  .width('75%')
}
.height(600)

在这个RowSplit中:

  1. 左侧区域是新闻分类区域,占总宽度的25%,背景色为浅灰色
  2. 右侧区域是新闻列表区域,占总宽度的75%
  3. 整个RowSplit的高度设置为600像素

左侧新闻分类区域

左侧新闻分类区域使用Column组件,包含一系列分类按钮:

Column() {
  ForEach(this.categories, (category: string) => {
    Button(category)
      .width('90%')
      .height(50)
      .fontSize(16)
      .margin({ top: 10 })
      .borderRadius(8)
      .backgroundColor(this.selectedCategory === category ? '#007DFF' : '#ffffff')
      .fontColor(this.selectedCategory === category ? '#ffffff' : '#333333')
      .onClick(() => {
        this.selectedCategory = category;
      })
  })
}
.width('25%')
.backgroundColor('#f5f5f5')
.padding({ top: 10 })

在这个区域中:

  1. 使用ForEach循环渲染所有分类按钮
  2. 每个按钮的宽度为父容器的90%,高度为50像素,上边距为10像素,圆角为8像素
  3. 根据selectedCategory状态设置按钮的背景色和文字颜色
  4. 添加onClick事件处理器,在点击时更新selectedCategory状态

右侧新闻列表区域

右侧新闻列表区域使用Column组件,包含一个List组件用于显示新闻列表:

Column() {
  List() {
    ForEach(this.newsData.filter(item => this.selectedCategory === '推荐' || item.category === this.selectedCategory), (item: NewsItem) => {
      ListItem() {
        this.NewsItemComponent(item)
      }
      .padding(10)
    })
  }
  .width('100%')
  .height('100%')
  .divider({ strokeWidth: 1, color: '#f0f0f0', startMargin: 10, endMargin: 10 })
}
.width('75%')

在这个区域中:

  1. 使用List组件显示新闻列表
  2. 使用ForEach循环渲染符合当前选中分类的新闻项
  3. 使用filter方法过滤新闻数据,只显示当前选中分类的新闻(如果选中的是"推荐",则显示所有新闻)
  4. 每个ListItem的内边距为10像素
  5. List组件的宽度和高度都设置为100%,确保充分利用可用空间
  6. 添加分割线,线宽为1像素,颜色为浅灰色,左右边距为10像素

新闻项组件

为了显示单条新闻,我们定义了一个NewsItemComponent方法:

@Builder
private NewsItemComponent(item: NewsItem) {
  Row() {
    Column() {
      Text(item.title)
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 5 })
      Row() {
        Text(item.source)
          .fontSize(14)
          .fontColor('#666')
        Text(item.time)
          .fontSize(14)
          .fontColor('#666')
          .margin({ left: 10 })
      }
    }
    .layoutWeight(1)
    .alignItems(HorizontalAlign.Start)

    Image(item.imageUrl)
      .width(100)
      .height(70)
      .objectFit(ImageFit.Cover)
      .borderRadius(5)
      .margin({ left: 10 })
  }
  .width('100%')
}

在这个方法中:

  1. 使用Row组件作为最外层容器,包含新闻信息和新闻图片
  2. 左侧使用Column组件显示新闻标题、来源和时间
    • 新闻标题使用16像素的粗体字体,下边距为5像素
    • 新闻来源和时间使用14像素的灰色字体,时间的左边距为10像素
    • Column组件的layoutWeight设置为1,确保它占据除图片外的所有可用空间
    • alignItems设置为HorizontalAlign.Start,确保文本左对齐
  3. 右侧使用Image组件显示新闻图片
    • 图片宽度为100像素,高度为70像素
    • 使用objectFit(ImageFit.Cover)确保图片填满区域并保持比例
    • 圆角为5像素,左边距为10像素

布局分析

水平分割的应用

在本案例中,我们使用RowSplit组件将界面分为左右两部分:

  1. 左侧区域(新闻分类区域)

    • 占总宽度的25%
    • 使用Column组件实现,垂直排列分类按钮
    • 背景色为浅灰色,与右侧区域形成视觉区分
  2. 右侧区域(新闻列表区域)

    • 占总宽度的75%
    • 使用Column组件包含一个List组件,显示新闻列表

这种水平分割的布局方式非常适合新闻阅读应用,使得用户可以方便地切换新闻分类,同时浏览当前分类的新闻列表。

列表的应用

在新闻列表区域,我们使用List组件显示新闻列表:

List() {
  ForEach(this.newsData.filter(item => this.selectedCategory === '推荐' || item.category === this.selectedCategory), (item: NewsItem) => {
    ListItem() {
      this.NewsItemComponent(item)
    }
    .padding(10)
  })
}
.width('100%')
.height('100%')
.divider({ strokeWidth: 1, color: '#f0f0f0', startMargin: 10, endMargin: 10 })

List组件的特点是可以高效地显示大量数据,并支持滚动和分割线等功能。在这个例子中,我们使用divider属性添加分割线,使新闻项之间有明确的视觉分隔。

循环渲染的应用

在本案例中,我们使用ForEach组件实现循环渲染,用于渲染新闻分类按钮和新闻列表项:

// 渲染新闻分类按钮
ForEach(this.categories, (category: string) => {
  Button(category)
    // 按钮属性
})

// 渲染新闻列表项
ForEach(this.newsData.filter(item => this.selectedCategory === '推荐' || item.category === this.selectedCategory), (item: NewsItem) => {
  ListItem() {
    this.NewsItemComponent(item)
  }
  .padding(10)
})

ForEach组件接收一个数组和一个回调函数,对数组中的每个元素调用回调函数来渲染对应的组件。在新闻列表的例子中,我们还使用filter方法过滤数据,只显示符合当前选中分类的新闻。

构建器的应用

在本案例中,我们使用@Builder装饰器定义了一个NewsItemComponent方法,用于构建新闻项组件:

@Builder
private NewsItemComponent(item: NewsItem) {
  // 组件内容
}

@Builder装饰器可以将一个方法转换为组件构建器,使得我们可以在多个地方重用相同的组件结构。在这个例子中,我们将新闻项的构建逻辑封装在NewsItemComponent方法中,使代码更加模块化和可维护。

布局技巧

比例设置

在本案例中,我们使用百分比来设置左右区域的宽度(width('25%')width('75%')),这样可以确保在不同屏幕尺寸下,左右区域的比例保持一致。

边距设置

我们为各个组件设置了适当的边距,确保界面布局美观:

  1. 外层Column设置了15的内边距,确保整个界面与屏幕边缘有适当的间距
  2. 分类按钮设置了10的上边距,确保按钮之间有适当的间距
  3. 新闻列表项设置了10的内边距,确保内容与边缘有适当的间距
  4. 新闻标题设置了5的下边距,确保标题和来源之间有适当的间距
  5. 新闻时间设置了10的左边距,确保来源和时间之间有适当的间距
  6. 新闻图片设置了10的左边距,确保文本和图片之间有适当的间距

文本样式设置

我们为不同类型的文本设置了不同的样式,使界面层次分明:

  1. 标题文本使用20像素的粗体字体,突出显示
  2. 新闻标题使用16像素的粗体字体,突出显示
  3. 新闻来源和时间使用14像素的灰色字体,区分主次信息

背景色设置

我们为左侧新闻分类区域设置了浅灰色背景(backgroundColor('#f5f5f5')),与右侧新闻列表区域形成视觉区分,使界面结构更加清晰。

选中状态设置

我们为分类按钮设置了选中状态,使用户可以清楚地知道当前选中的是哪个分类:

.backgroundColor(this.selectedCategory === category ? '#007DFF' : '#ffffff')
.fontColor(this.selectedCategory === category ? '#ffffff' : '#333333')

当按钮被选中时,背景色变为蓝色,文字颜色变为白色;当按钮未被选中时,背景色为白色,文字颜色为深灰色。

总结

在本教程中,我们学习了如何使用HarmonyOS NEXT的RowSplit组件构建一个新闻阅读应用界面。通过水平分割布局,我们将界面分为新闻分类区域和新闻列表区域,使得界面结构清晰,信息展示合理。

收藏00

登录 后评论。没有帐号? 注册 一个。

全栈若城

  • 0回答
  • 4粉丝
  • 0关注