【Harmonyos】开源鸿蒙跨平台训练营DAY9:获取分类数据并渲染

Flutter鸿蒙开发指南(九):获取分类数据并渲染


🌸你好呀!我是 lbb小魔仙
🌟 感谢陪伴~ 小白博主在线求友
🌿 跟着小白学Linux/Java/Python
📖 专栏汇总:
《Linux》专栏 | 《Java》专栏 | 《Python》专栏

前言

在电商应用中,分类数据是核心功能之一。本文将详细介绍如何在 Flutter/HarmonyOS 项目中实现分类数据的获取与渲染功能,完整展示从 API 接口定义到 UI 展示的完整流程。

一、实现流程

按照规范的七步开发流程:

复制代码
(1)定义常量数据、基础地址、超时时间、业务状态、请求地址
(2)封装网络请求工具,基础地址,拦截器
(3)请求工具进一步解构,处理http状态和业务状态
(4)类工厂转化动态类型到对象类型
(5)封装请求API调用工厂函数
(6)更新页面组件接收参数
(7)初始化数据更新状态

1.1 分类接口介绍

接口地址https://meikou-api.itheima.net/home/category/head

返回数据示例

json 复制代码
{
  "code": "1",
  "result": [
    {
      "id": "1181622001",
      "name": "气质女装",
      "picture": "https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/meikou/c1/qznz.png",
      "children": [
        {
          "id": "1191110001",
          "name": "半裙",
          "picture": "https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/meikou/c2/qznz_bq.png"
        }
      ]
    }
  ]
}

二、代码实现

2.1 定义接口常量

文件lib/constants/index.dart

dart 复制代码
// 存放请求地址接口的常量
class HttpConstants {
  // 轮播图接口
  static const String BANNER_LIST = "/home/banner";

  // 分类列表接口
  static const String CATEGORY_LIST = "/home/category/head";
}

2.2 构建数据模型

文件lib/viewmodels/home.dart

dart 复制代码
// 每一个分类具体类型
class CategoryItem {
  String id;
  String name;
  String picture;
  List<CategoryItem>? children;

  CategoryItem({
    required this.id,
    required this.name,
    required this.picture,
    this.children,
  });

  // 工厂函数:从JSON创建对象
  factory CategoryItem.formJSON(Map<String, dynamic> json) {
    return CategoryItem(
      id: json["id"] ?? "",
      name: json["name"] ?? "",
      picture: json["picture"] ?? "",
      children: json["children"] == null
          ? null
          : (json["children"] as List)
              .map((item) => CategoryItem.formJSON(item as Map<String, dynamic>))
              .toList(),
    );
  }
}

关键点

  • 使用 factory 关键字声明工厂函数
  • 使用空安全操作符 ?? 提供默认值
  • 递归处理 children 嵌套结构

2.3 封装 API 调用

文件lib/api/home.dart

dart 复制代码
/// 获取分类列表数据
Future<List<CategoryItem>> getCategoryListAPI() async {
  // 发起请求并转换数据
  final result = ((await dioRequest.get(HttpConstants.CATEGORY_LIST)) as List)
      .map((item) {
    return CategoryItem.formJSON(item as Map<String, dynamic>);
  }).toList();
  return result;
}

2.4 更新分类组件

文件lib/components/Home/HmCategory.dart

dart 复制代码
import 'package:flutter/material.dart';
import 'package:harmonyos_day_four/viewmodels/home.dart';

class HmCategory extends StatefulWidget {
  // 分类列表
  final List<CategoryItem> categoryList;
  const HmCategory({super.key, required this.categoryList});

  @override
  State<HmCategory> createState() => _HmCategoryState();
}

class _HmCategoryState extends State<HmCategory> {
  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 100,
      child: ListView.builder(
          scrollDirection: Axis.horizontal,
          itemCount: widget.categoryList.length,
          itemBuilder: (BuildContext context, int index) {
            final categoryItem = widget.categoryList[index];
            return Container(
              alignment: Alignment.center,
              width: 80,
              height: 100,
              decoration: BoxDecoration(
                color: const Color.fromARGB(255, 231, 232, 234),
                borderRadius: BorderRadius.circular(40),
              ),
              margin: const EdgeInsets.symmetric(horizontal: 10),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Image.network(categoryItem.picture, width: 40, height: 40),
                  Text(categoryItem.name,
                      style: const TextStyle(color: Colors.black)),
                ],
              ),
            );
          }),
    );
  }
}

2.5 首页获取数据

文件lib/pages/home/index.dart

dart 复制代码
class _HomeViewState extends State<HomeView> {
  // 分类列表
  List<CategoryItem> _categoryList = [];

  // 轮播图列表
  List<BannerItem> _bannerList = [];

  @override
  void initState() {
    super.initState();
    _getBannederList();
    _getCategoryList();  // 获取分类数据
  }

  // 获取分类列表
  void _getCategoryList() async {
    try {
      _categoryList = await getCategoryListAPI();
      setState(() {});
    } catch (e) {
      print('获取分类数据失败: $e');
    }
  }

  // 在滚动视图中使用
  List<Widget> _getScrollChildren() {
    return [
      SliverToBoxAdapter(child: HmSlider(bannerList: _bannerList)),
      const SliverToBoxAdapter(child: SizedBox(height: 10)),
      SliverToBoxAdapter(child: HmCategory(categoryList: _categoryList)), // 分类组件
      // ...
    ];
  }
}

三、遇到问题及解决方法

问题1:空安全类型转换错误

错误现象

复制代码
type 'Null' is not a subtype of type 'String'

原因分析 :API 返回的数据中某些字段可能为 null,直接使用 json["id"] 会导致类型错误。

解决方法 :使用空安全操作符 ?? 提供默认值

dart 复制代码
// ❌ 错误写法
id: json["id"]

// ✅ 正确写法
id: json["id"] ?? ""

问题2:嵌套 children 数组解析失败

错误现象

复制代码
type 'List<dynamic>' is not a subtype of type 'List<CategoryItem>'

原因分析 :JSON 解析后的 childrenList<dynamic> 类型,需要手动转换。

解决方法 :使用 map 进行类型转换

dart 复制代码
children: json["children"] == null
    ? null
    : (json["children"] as List)
        .map((item) => CategoryItem.formJSON(item as Map<String, dynamic>))
        .toList(),

问题3:UI 显示异常

错误现象:分类数据加载后,UI 没有更新显示

原因分析 :异步数据获取后没有调用 setState 更新界面

解决方法 :在 setState 回调中更新数据

dart 复制代码
void _getCategoryList() async {
  try {
    _categoryList = await getCategoryListAPI();
    setState(() {});  // 必须调用 setState 触发 UI 更新
  } catch (e) {
    print('获取分类数据失败: $e');
  }
}

问题4:组件参数传递错误

错误现象

复制代码
The named parameter 'categoryList' is required but wasn't provided

原因分析HmCategory 组件添加了必需参数 categoryList,但调用时没有传递

解决方法:在组件调用时传递参数

dart 复制代码
// ❌ 错误写法
const SliverToBoxAdapter(child: HmCategory()),

// ✅ 正确写法
SliverToBoxAdapter(child: HmCategory(categoryList: _categoryList)),

四、效果展示

分类列表以横向滚动方式展示,每个分类项包含:

  • 圆角背景容器(灰色)

  • 分类图标(网络图片)

  • 分类名称(黑色文字)

    ┌────────────────────────────────────────────────────────────┐
    │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
    │ │ 图标 │ │ 图标 │ │ 图标 │ │ 图标 │ │ 图标 │ ... │
    │ │名称 │ │名称 │ │名称 │ │名称 │ │名称 │ │
    │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
    │ ← 横向滚动 → │
    └────────────────────────────────────────────────────────────┘

五、总结

本文介绍了 Flutter/HarmonyOS 电商应用中分类数据获取与渲染的完整实现流程:

  1. 数据模型:使用工厂模式实现 JSON 到对象的转换
  2. 网络请求:封装 API 调用,统一处理业务状态码
  3. UI 渲染:横向滚动列表展示分类数据
  4. 错误处理:空安全、类型转换、状态更新

通过遵循规范的七步开发流程,可以快速实现类似的数据获取与展示功能。

源码地址

https://atomgit.com/lbbxmx111/haromyos_day_four

欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net

📕个人领域 :Linux/C++/java/AI

🚀 个人主页有点流鼻涕 · CSDN

💬 座右铭 : "向光而行,沐光而生。"

相关推荐
程序员老刘1 小时前
Flutter 3.41 更新要点速评:主打优化,避坑AGP 9
flutter·客户端
2601_949593652 小时前
进阶实战 Flutter for OpenHarmony:GestureDetector 高级手势系统 - 多点触控与手势竞争处理
flutter
2601_949593653 小时前
进阶实战 Flutter for OpenHarmony:Notification 组件实战 - 事件冒泡传递
flutter
加农炮手Jinx4 小时前
Flutter for OpenHarmony:web_socket_channel 全平台 WebSocket 通信标准库,从原理到鸿蒙实战(3000字深度解析)
android·前端·网络·websocket·flutter·华为·harmonyos
王码码20354 小时前
Flutter for OpenHarmony:stomp_dart_client 打造实时消息引擎(企业级 WebSocket 通信标准) 深度解析与鸿蒙适配指南
网络·websocket·网络协议·flutter·ui·华为·harmonyos
王码码20354 小时前
Flutter for OpenHarmony:web_socket 纯 Dart 标准 WebSocket 客户端(跨平台兼容性之王) 深度解析与鸿蒙
android·前端·websocket·网络协议·flutter·华为·harmonyos
心之语歌5 小时前
flutter provider 使用,状态管理更新跨组件数据共享
后端·flutter
松叶似针6 小时前
Flutter三方库适配OpenHarmony【secure_application】— 生产环境发布与持续维护
flutter·harmonyos
星空22237 小时前
【HarmonyOS】RN_of_HarmonyOS实战项目:URL链接输入
华为·harmonyos
FrameNotWork7 小时前
HarmonyOS 实现仿抖音上下滑动照片浏览(弹簧阻尼动画详解)
华为·harmonyos