基于前面的贴着,接着完善下鸿蒙项目的开发,完善每个选项卡对应页面的完整实现。


一、项目概述

这是一款以作品流为核心的 鸿蒙 应用,采用底部四宫格导航:首页、发现、消息、我的。各页面功能独立,通过统一的作品数据源与作品详情页形成协同。

特性 说明
技术栈 Flutter,Dio 网络请求,Material 3
数据来源 远程 JS 资源解析为作品列表与图片 URL
展示形态 首页竖滑流 + 发现网格搜索 + 消息会话 + 个人中心
刘海屏UI 对刘海屏顶部的处理

二、功能模块

2.1 首页(Home)

在这前面文章中已经学习并完成了首页全部的逻辑 【开源鸿蒙跨平台开发先锋训练营】Flutter实现列表上拉加载和下拉刷新

2.2 发现(Search)

在这里插入图片描述

入口:底部导航「发现」。

布局

  • 顶部 AppBar 内嵌搜索框:圆角、占位文案「搜索作品、风格、作者、标签」、前缀搜索图标;右侧刷新按钮;空出刘海屏空间,不布局内容,保证内容显示的完整性。
  • 主体为两列网格作品卡片;空态/错误态居中提示。

数据与筛选

  • 与首页相同数据源:ApiService + DataParser.parseWorksAndImages() 获取作品列表。
  • 搜索框实时过滤:关键词匹配作品标题、风格(style)、场景(scene)、作者名、标签(tags),不区分大小写;清空搜索则恢复全部作品。
// 搜索关键词实时过滤
void _onSearchChanged(String kw) {
  final keyword = kw.trim().toLowerCase();
  setState(() {
    _filteredWorks = keyword.isEmpty ? _allWorks :
      _allWorks.where((w) =>
        w.title.toLowerCase().contains(keyword) ||
        w.style.toLowerCase().contains(keyword) ||
        w.scene.toLowerCase().contains(keyword) ||
        w.author.name.toLowerCase().contains(keyword) ||
        w.tags.any((t) => t.toLowerCase().contains(keyword))
      ).toList();
  });
}

// 卡片点击查看详情
void _onCardTap(WorkModel work) {
  Navigator.push(context, MaterialPageRoute(
    builder: (_) => WorkDetailPage(work: work, initialIndex: 0)));
}

在这里插入图片描述

交互

  • 点击卡片:进入作品详情页WorkDetailPage(work, 0),传入该作品与 initialIndex: 0
  • 下拉刷新:重新请求并更新列表。
  • 参考:lib/pages/search_page.dart

依赖

  • lib/pages/search_page.dart
  • lib/pages/work_detail_page.dartlib/models/work_model.dartlib/api/api_service.dartlib/utils/data_parser.dartlib/widgets/network_image_widget.dart

2.3 消息(Messages)

在这里插入图片描述

入口:底部导航「消息」。

布局

  • 标题「消息」,右侧可放置「添加」等入口。
  • 会话列表:每项展示头像、会话名称、最后一条消息预览、时间、未读数角标;无会话时显示空态(图标 + 文案「暂无消息」)。

数据

  • 使用 ConversationModel(id、name、avatarUrl、lastMessage、lastTime、unreadCount)与 MessageModel(id、content、isMe、time)。
  • 当前为本地模拟会话与消息,无真实后端。
// 聊天页发送消息回调
void _onMessageSent(String content) {
  setState(() {
    _conversation.lastMessage = content;
    _conversation.lastTime = DateTime.now();
    widget.onUpdated(_conversation); // 上层列表刷新未读与内容
  });
}

交互

  • 点击会话:进入聊天详情页ChatDetailPage)。
  • 聊天详情页:
    • 顶部标题为会话名称。
    • 中部为消息列表(气泡:己方右对齐、对方左对齐,带时间)。
    • 底部输入框 + 发送按钮;发送后本地追加一条己方消息,并回调 onMessageSent(content) 更新会话列表的「最后一条消息」与时间,形成闭环。

依赖

  • lib/pages/messages_page.dart
  • lib/models/message_model.dart

2.4 我的(Profile)

在这里插入图片描述

入口:底部导航「我的」。

布局

  • 标题「我的」,右侧设置图标(可进入设置页)。
  • 用户信息区:头像、昵称、获赞 / 收藏统计(基于当前拉取作品的 likes/saves 汇总,示例逻辑)。
  • 功能列表:历史记录、设置、退出登录;每项带图标与副标题,右侧箭头。

数据

  • 用户信息为占位(如「示例用户」)。
  • 历史记录:复用 ApiService + DataParser 拉取作品,取前若干条(如 6 条)作为「最近浏览」展示;统计数为作品维度汇总。

交互

  • 历史记录:进入历史记录页,列表展示作品缩略图、标题、作者;点击某项 → 进入作品详情页
  • 设置:进入设置子页(通知、隐私、清除缓存等入口,具体逻辑可后续实现)。
  • 退出登录:弹出确认对话框;确认后执行退出逻辑(当前为示例提示)。
// 获取最近浏览历史
List<WorkModel> getRecentHistory(int n) {
  return _allWorks.take(n).toList();
}

// 退出登录操作
void _onLogout() async {
  final ok = await showDialog(...);
  if (ok == true) {
    // 执行登出逻辑
  }
}

依赖

  • lib/pages/profile_page.dart
  • lib/pages/work_detail_page.dartlib/models/work_model.dartlib/api/api_service.dartlib/utils/data_parser.dart

2.5 作品详情页(WorkDetail)

入口:首页(点击大图)、发现(点击卡片)、我的(历史记录点击)。

布局

  • 全屏黑色背景;竖向 PageView 展示该作品多张图片,左右/上下滑动切换(与首页一致为竖向)。
  • 顶部:返回按钮 + 当前张数 / 总张数。
  • 底部渐变条:作品标题、风格/场景标签、作者头像与名称、平台、点赞数/收藏数。

在这里插入图片描述

数据

  • 入参:WorkModel workint initialIndex(首屏显示的图片索引)。
// 切换图片更新索引
void _onPageChanged(int idx) {
  setState(() {
    _currentIndex = idx;
  });
}

// 返回上一层
void _onBack() {
  Navigator.pop(context);
}

交互

  • 返回:关闭当前页回到上一页(首页/发现/我的或历史列表)。

依赖

  • lib/pages/work_detail_page.dart
  • lib/models/work_model.dartlib/widgets/network_image_widget.dart

三、数据模型与接口

3.1 作品与作者(WorkModel / AuthorModel)

  • WorkModel:id、title、images(图片 URL 列表)、style、scene、tags、author、likes、saves、votes、rank、isEditorPick、createdAt。
  • AuthorModel:id、name、avatar、platform、platformUrl。
  • 定义于 lib/models/work_model.dart,支持 fromJson / toJson

3.2 消息与会话(MessageModel / ConversationModel)

  • ConversationModel:id、name、avatarUrl、lastMessage、lastTime、unreadCount。
  • MessageModel:id、content、isMe、time。
  • 定义于 lib/models/message_model.dart,当前仅前端使用,无持久化。

3.3 数据获取与解析

  • ApiServicelib/api/api_service.dart):单例,Dio 封装;getMockData() 请求指定 JS 资源并返回原始数据(字符串或已解析 JSON)。
  • DataParserlib/utils/data_parser.dart):从 JS 内容中提取 JSON 数组,解析为 WorkModel 列表,并汇总所有图片 URL;对外主要使用 parseWorksAndImages(jsContent),返回 { 'works': List<WorkModel>, 'images': List<String> }

3.4 图片加载

  • NetworkImageWidgetlib/widgets/network_image_widget.dart):使用 Dio 以字节方式下载图片并展示,带加载中/失败态,便于在目标平台上稳定展示网络图。

四、页面与导航结构

RootPage(底部导航)
├── 首页 → HomePage
│         └── 点击大图 → WorkDetailPage(work, index)
├── 发现 → SearchPage
│         └── 点击卡片 → WorkDetailPage(work, 0)
├── 消息 → MessagesPage
│         └── 点击会话 → ChatDetailPage(conversation)
└── 我的 → ProfilePage
          ├── 历史记录 → _HistoryPage → 点击项 → WorkDetailPage(work)
          ├── 设置 → 设置子页
          └── 退出登录 → 确认对话框
  • 首页、发现、我的共用同一作品数据源WorkDetailPage,保证从任意入口进入的作品详情体验一致。
  • 消息模块独立,通过会话列表与聊天详情的回调保持「最后一条消息」等状态同步。

五、技术实现要点

要点 说明
首页分页 维护 _images 全量与 _displayImages 当前页,滑动接近末尾触发 _loadMore()
首页→详情映射 根据当前图片 URL 在 _works 中查找包含该 URL 的作品及在作品内的索引,再打开 WorkDetailPage。
发现搜索 搜索框 onChanged 中按关键词过滤 _allWorks 得到 _filteredWorks,网格绑定 _filteredWorks
消息闭环 ChatDetailPage 发送消息时调用 onMessageSent(content),MessagesPage 更新对应会话的 lastMessage、lastTime。
我的历史 ProfilePage 初始化或刷新时请求作品数据,取前几条作为历史列表;历史页点击跳转 WorkDetailPage。
统一图片组件 列表/详情中的网络图均使用 NetworkImageWidget,保证加载与错误表现一致。

结束语

感谢阅读本帖,如对贴中内容有意见和建议的,欢迎与我联系交流,也欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐