【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

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

相关推荐
mocoding3 小时前
Flutter 3D 翻转动画flip_card三方库在鸿蒙版天气预报卡片中的实战教程
flutter·3d·harmonyos
2501_920931704 小时前
React Native鸿蒙跨平台实现推箱子游戏,完成玩家移动与箱子推动,当所有箱子都被推到目标位置时,玩家获胜
javascript·react native·react.js·游戏·ecmascript·harmonyos
C雨后彩虹5 小时前
计算疫情扩散时间
java·数据结构·算法·华为·面试
2601_949809595 小时前
flutter_for_openharmony家庭相册app实战+我的Tab实现
java·javascript·flutter
24zhgjx-lxq5 小时前
华为ensp:MSTP
网络·安全·华为·hcip·ensp
2601_949868365 小时前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter
qq_177767376 小时前
React Native鸿蒙跨平台数据使用监控应用技术,通过setInterval每5秒更新一次数据使用情况和套餐使用情况,模拟了真实应用中的数据监控场景
开发语言·前端·javascript·react native·react.js·ecmascript·harmonyos
烬头88216 小时前
React Native鸿蒙跨平台应用实现了onCategoryPress等核心函数,用于处理用户交互和状态更新,通过计算已支出和剩余预算
前端·javascript·react native·react.js·ecmascript·交互·harmonyos
一起养小猫6 小时前
Flutter for OpenHarmony 实战:别踩白方块游戏完整开发指南
flutter·游戏