【Harmonyos】开源鸿蒙跨平台训练营DAY5:Flutter电商首页+底部导航栏开发教程

Flutter × OpenHarmony:从零实现电商首页 + 底部导航栏(完整流程 + 踩坑记录)


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

  • [Flutter × OpenHarmony:从零实现电商首页 + 底部导航栏(完整流程 + 踩坑记录)](#Flutter × OpenHarmony:从零实现电商首页 + 底部导航栏(完整流程 + 踩坑记录))
    • 前言
    • 一、项目目标
    • 二、详细开发流程
      • [2.1 创建 Flutter 项目](#2.1 创建 Flutter 项目)
      • [2.2 创建项目目录结构](#2.2 创建项目目录结构)
      • [2.3 创建组件模板](#2.3 创建组件模板)
      • [2.4 实现各个组件](#2.4 实现各个组件)
        • [(1)轮播图组件 `HmSlider.dart`](#(1)轮播图组件 HmSlider.dart)
        • [(2)分类组件 `HmCategory.dart`(横向滚动)](#(2)分类组件 HmCategory.dart(横向滚动))
        • [(3)推荐组件 `HmSuggestion.dart`](#(3)推荐组件 HmSuggestion.dart)
        • [(4)爆款推荐组件 `HmHot.dart`](#(4)爆款推荐组件 HmHot.dart)
        • [(5)商品列表组件 `HmMoreList.dart`(网格布局)](#(5)商品列表组件 HmMoreList.dart(网格布局))
      • [2.5 组装首页 `pages/home/index.dart`](#2.5 组装首页 pages/home/index.dart)
      • [2.6 创建其他页面](#2.6 创建其他页面)
        • [分类页面 `pages/category/index.dart`](#分类页面 pages/category/index.dart)
        • [购物车页面 `pages/cart/index.dart`](#购物车页面 pages/cart/index.dart)
        • [我的页面 `pages/profile/index.dart`](#我的页面 pages/profile/index.dart)
      • [2.7 创建底部导航栏主框架 `pages/main/index.dart`](#2.7 创建底部导航栏主框架 pages/main/index.dart)
      • [2.8 修改应用入口 `main.dart`](#2.8 修改应用入口 main.dart)
    • 三、核心知识点总结
      • [3.1 CustomScrollView + Sliver 体系](#3.1 CustomScrollView + Sliver 体系)
      • [3.2 布局组件对比](#3.2 布局组件对比)
      • [3.3 BottomNavigationBar 使用要点](#3.3 BottomNavigationBar 使用要点)
    • 四、遇到的问题及解决方案
      • [问题 1:CustomScrollView 报错 "All children must be Sliver widgets"](#问题 1:CustomScrollView 报错 "All children must be Sliver widgets")
      • [问题 2:ListView 横向滚动后高度失效](#问题 2:ListView 横向滚动后高度失效)
      • [问题 3:底部导航栏图标不显示/显示异常](#问题 3:底部导航栏图标不显示/显示异常)
      • [问题 4:组件内边距不生效](#问题 4:组件内边距不生效)
      • [问题 5:DevEco Studio 路径问题](#问题 5:DevEco Studio 路径问题)
    • 五、项目运行
      • [在 DevEco Studio 中运行](#在 DevEco Studio 中运行)
      • 运行效果
    • 六、总结

前言

本文将详细记录使用 Flutter 开发鸿蒙电商应用首页的完整过程,包括组件化设计、CustomScrollView 滚动布局、底部导航栏实现,以及在开发过程中遇到的问题和解决方案。

项目环境:

  • Flutter SDK 3.x
  • Dart 3.x
  • DevEco Studio
  • HarmonyOS API 9+

一、项目目标

  1. 实现电商首页基础布局(轮播图、分类、推荐、爆款、商品列表)
  2. 实现底部导航栏(首页、分类、购物车、我的)
  3. 采用组件化设计,提升代码复用性

二、详细开发流程

2.1 创建 Flutter 项目

bash 复制代码
flutter create harmonyos_day_four
cd harmonyos_day_four

2.2 创建项目目录结构

复制代码
lib/
├── components/
│   └── Home/
│       ├── HmSlider.dart      # 轮播图组件
│       ├── HmCategory.dart    # 分类组件
│       ├── HmSuggestion.dart  # 推荐组件
│       ├── HmHot.dart         # 爆款推荐组件
│       └── HmMoreList.dart    # 商品列表组件
├── pages/
│   ├── home/
│   │   └── index.dart         # 首页
│   ├── category/
│   │   └── index.dart         # 分类页面
│   ├── cart/
│   │   └── index.dart         # 购物车页面
│   ├── profile/
│   │   └── index.dart         # 我的页面
│   └── main/
│       └── index.dart         # 底部导航主框架
└── main.dart                  # 应用入口

创建目录命令:

bash 复制代码
cd lib
mkdir components components/Home
mkdir pages pages/home pages/category pages/cart pages/profile pages/main

2.3 创建组件模板

在每个组件文件中输入 stful 快捷键,自动生成 StatefulWidget 模板:

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

class HmSlider extends StatefulWidget {
  const HmSlider({super.key});

  @override
  State<HmSlider> createState() => _HmSliderState();
}

class _HmSliderState extends State<HmSlider> {
  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

2.4 实现各个组件

(1)轮播图组件 HmSlider.dart
dart 复制代码
import 'package:flutter/material.dart';

class HmSlider extends StatefulWidget {
  const HmSlider({super.key});

  @override
  State<HmSlider> createState() => _HmSliderState();
}

class _HmSliderState extends State<HmSlider> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 10), // 添加左右内边距
      child: Container(
        color: Colors.blue,
        height: 300,
        alignment: Alignment.center,
        child: const Text(
          '轮播图',
          style: TextStyle(color: Colors.white, fontSize: 20),
        ),
      ),
    );
  }
}
(2)分类组件 HmCategory.dart(横向滚动)
dart 复制代码
import 'package:flutter/material.dart';

class HmCategory extends StatefulWidget {
  const HmCategory({super.key});

  @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: 10,
        itemBuilder: (BuildContext context, int index) {
          return Container(
            alignment: Alignment.center,
            width: 80,
            height: 100,
            color: Colors.blue,
            child: Text("分类$index", style: const TextStyle(color: Colors.white)),
            margin: const EdgeInsets.symmetric(horizontal: 10),
          );
        },
      ),
    );
  }
}
(3)推荐组件 HmSuggestion.dart
dart 复制代码
import 'package:flutter/material.dart';

class HmSuggestion extends StatefulWidget {
  const HmSuggestion({super.key});

  @override
  State<HmSuggestion> createState() => _HmSuggestionState();
}

class _HmSuggestionState extends State<HmSuggestion> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 10), // 添加左右内边距
      child: Container(
        color: Colors.blue,
        alignment: Alignment.center,
        height: 300,
        child: const Text(
          "推荐",
          style: TextStyle(color: Colors.white),
        ),
      ),
    );
  }
}
(4)爆款推荐组件 HmHot.dart
dart 复制代码
import 'package:flutter/material.dart';

class HmHot extends StatefulWidget {
  const HmHot({super.key});

  @override
  State<HmHot> createState() => _HmHotState();
}

class _HmHotState extends State<HmHot> {
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 200,
      color: Colors.blue,
      alignment: Alignment.center,
      child: const Text(
        '爆款推荐',
        style: TextStyle(color: Colors.white),
      ),
    );
  }
}
(5)商品列表组件 HmMoreList.dart(网格布局)
dart 复制代码
import 'package:flutter/material.dart';

class HmMorelist extends StatefulWidget {
  const HmMorelist({super.key});

  @override
  State<HmMorelist> createState() => _HmMorelistState();
}

class _HmMorelistState extends State<HmMorelist> {
  @override
  Widget build(BuildContext context) {
    return SliverGrid.builder(
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,     // 两列网格
        mainAxisSpacing: 10,    // 纵向间距
        crossAxisSpacing: 10,   // 横向间距
      ),
      itemBuilder: (BuildContext context, int index) {
        return Container(
          child: const Text(
            "商品",
            style: TextStyle(color: Colors.white),
          ),
          color: Colors.blue,
          alignment: Alignment.center,
        );
      },
    );
  }
}

2.5 组装首页 pages/home/index.dart

dart 复制代码
import 'package:flutter/cupertino.dart';
import 'package:harmonyos_day_four/components/Home/HmCategory.dart';
import 'package:harmonyos_day_four/components/Home/HmHot.dart';
import 'package:harmonyos_day_four/components/Home/HmMoreList.dart';
import 'package:harmonyos_day_four/components/Home/HmSlider.dart';
import 'package:harmonyos_day_four/components/Home/HmSuggestion.dart';

class HomeView extends StatefulWidget {
  const HomeView({super.key});

  @override
  State<HomeView> createState() => _HomeViewState();
}

class _HomeViewState extends State<HomeView> {
  // 获取滚动容器的内容
  List<Widget> _getScrollChildren() {
    return [
      const SliverToBoxAdapter(child: HmSlider()),           // 轮播图
      const SliverToBoxAdapter(child: SizedBox(height: 10)),
      const SliverToBoxAdapter(child: HmCategory()),         // 分类
      const SliverToBoxAdapter(child: SizedBox(height: 10)),
      const SliverToBoxAdapter(child: HmSuggestion()),       // 推荐
      const SliverToBoxAdapter(child: SizedBox(height: 10)),

      // Flex + Expanded 实现横向均分布局(两个爆款推荐)
      SliverToBoxAdapter(
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 10),
          child: Flex(
            direction: Axis.horizontal,
            children: [
              const Expanded(child: HmHot()),
              const SizedBox(width: 10),
              Expanded(child: HmHot()),
            ],
          ),
        ),
      ),
      const SliverToBoxAdapter(child: SizedBox(height: 10)),
      const HmMorelist(),                                    // 商品网格
    ];
  }

  @override
  Widget build(BuildContext context) {
    // CustomScrollView 要求:必须是 sliver 家族的内容
    return CustomScrollView(slivers: _getScrollChildren());
  }
}

2.6 创建其他页面

分类页面 pages/category/index.dart
dart 复制代码
import 'package:flutter/material.dart';

class CategoryView extends StatefulWidget {
  const CategoryView({super.key});

  @override
  State<CategoryView> createState() => _CategoryViewState();
}

class _CategoryViewState extends State<CategoryView> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('分类'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(Icons.category, size: 100, color: Colors.blue),
            SizedBox(height: 20),
            Text(
              '分类页面',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
          ],
        ),
      ),
    );
  }
}
购物车页面 pages/cart/index.dart
dart 复制代码
import 'package:flutter/material.dart';

class CartView extends StatefulWidget {
  const CartView({super.key});

  @override
  State<CartView> createState() => _CartViewState();
}

class _CartViewState extends State<CartView> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('购物车'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(Icons.shopping_cart, size: 100, color: Colors.orange),
            SizedBox(height: 20),
            Text(
              '购物车页面',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
          ],
        ),
      ),
    );
  }
}
我的页面 pages/profile/index.dart
dart 复制代码
import 'package:flutter/material.dart';

class ProfileView extends StatefulWidget {
  const ProfileView({super.key});

  @override
  State<ProfileView> createState() => _ProfileViewState();
}

class _ProfileViewState extends State<ProfileView> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('我的'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(Icons.person, size: 100, color: Colors.green),
            SizedBox(height: 20),
            Text(
              '我的页面',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
          ],
        ),
      ),
    );
  }
}

2.7 创建底部导航栏主框架 pages/main/index.dart

dart 复制代码
import 'package:flutter/material.dart';
import 'package:harmonyos_day_four/pages/home/index.dart';
import 'package:harmonyos_day_four/pages/category/index.dart';
import 'package:harmonyos_day_four/pages/cart/index.dart';
import 'package:harmonyos_day_four/pages/profile/index.dart';

class MainContainer extends StatefulWidget {
  const MainContainer({super.key});

  @override
  State<MainContainer> createState() => _MainContainerState();
}

class _MainContainerState extends State<MainContainer> {
  // 当前选中的页面索引
  int _currentIndex = 0;

  // 页面列表
  final List<Widget> _pages = [
    const HomeView(),
    const CategoryView(),
    const CartView(),
    const ProfileView(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _pages[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: (index) {
          setState(() {
            _currentIndex = index;
          });
        },
        type: BottomNavigationBarType.fixed,
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: '首页',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.category),
            label: '分类',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.shopping_cart),
            label: '购物车',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: '我的',
          ),
        ],
      ),
    );
  }
}

2.8 修改应用入口 main.dart

dart 复制代码
import 'package:flutter/material.dart';
import 'package:harmonyos_day_four/pages/main/index.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'HarmonyOS Day Four',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MainContainer(),
    );
  }
}

三、核心知识点总结

3.1 CustomScrollView + Sliver 体系

CustomScrollView 是 Flutter 中实现混合滚动的核心组件,它要求所有子组件必须是 Sliver 家族:

组件 用途
SliverToBoxAdapter 将普通 Widget 转为 Sliver
SliverGrid.builder 网格布局 Sliver
SliverList.builder 列表布局 Sliver
SliverAppBar 可滚动的应用栏

3.2 布局组件对比

组件 用途 关键属性
Flex 弹性布局容器 direction: Axis.horizontal/vertical
Expanded 占据剩余空间 配合 Flex 使用实现均分
Padding 内边距 padding: EdgeInsets.symmetric(horizontal: 10)
SizedBox 固定尺寸/间距 height: 10 / width: 10

3.3 BottomNavigationBar 使用要点

dart 复制代码
BottomNavigationBar(
  currentIndex: _currentIndex,        // 当前选中索引
  onTap: (index) { ... },             // 点击回调
  type: BottomNavigationBarType.fixed, // 固定模式(4+个Tab必选)
  items: [ ... ],                     // 导航项列表
)

四、遇到的问题及解决方案

问题 1:CustomScrollView 报错 "All children must be Sliver widgets"

错误信息:

复制代码
FlutterError (All children of a CustomScrollView must be Sliver widgets.
A Container was found, but Slivers are expected.)

原因分析:
CustomScrollViewslivers 参数只接受 Sliver 家族组件,不能直接放入普通 Widget 如 Container

解决方案:

使用 SliverToBoxAdapter 包裹普通组件:

dart 复制代码
// ❌ 错误写法
CustomScrollView(
  slivers: [
    Container(...),  // 报错
  ],
)

// ✅ 正确写法
CustomScrollView(
  slivers: [
    SliverToBoxAdapter(child: Container(...)),  // 正确
  ],
)

问题 2:ListView 横向滚动后高度失效

问题描述:

ListView.scrollDirection 设置为 Axis.horizontal 后,容器高度变为 0。

原因分析:
ListView 在横向滚动时,无法自动推断高度,需要父组件指定。

解决方案:

使用 SizedBoxContainer 包裹并设置高度:

dart 复制代码
SizedBox(
  height: 100,  // 必须指定高度
  child: ListView.builder(
    scrollDirection: Axis.horizontal,
    itemBuilder: (context, index) => Container(...),
  ),
)

问题 3:底部导航栏图标不显示/显示异常

问题描述:

当底部导航项超过 3 个时,图标和文字显示异常。

原因分析:
BottomNavigationBar 默认是 shifting 模式,只支持 3 个以内的 Tab。

解决方案:

明确设置 type: BottomNavigationBarType.fixed

dart 复制代码
BottomNavigationBar(
  type: BottomNavigationBarType.fixed,  // 固定模式
  items: [
    BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
    BottomNavigationBarItem(icon: Icon(Icons.category), label: '分类'),
    BottomNavigationBarItem(icon: Icon(Icons.shopping_cart), label: '购物车'),
    BottomNavigationBarItem(icon: Icon(Icons.person), label: '我的'),
  ],
)

问题 4:组件内边距不生效

问题描述:

组件与屏幕边缘紧贴,没有间距。

原因分析:

没有使用 Padding 组件包裹内容。

解决方案:

在需要间距的组件外包裹 Padding

dart 复制代码
return Padding(
  padding: const EdgeInsets.symmetric(horizontal: 10),  // 左右各10间距
  child: Container(...),
);

问题 5:DevEco Studio 路径问题

问题描述:

项目路径与创建时的项目名称不一致。

解决方案:

确认实际项目路径,注意拼写是否正确(如 harmonyos_dya_four vs harmonyos_day_four)。


五、项目运行

在 DevEco Studio 中运行

  1. 打开 DevEco Studio
  2. FileOpen → 选择项目目录
  3. 确保已安装 Flutter 和 Dart 插件
  4. 选择 HarmonyOS 模拟器或真机
  5. 点击运行按钮 ▶️

运行效果

  • 首页:完整的电商首页布局,支持上下滚动
  • 底部导航栏:4 个 Tab(首页、分类、购物车、我的)
  • 页面切换:点击底部导航栏可切换页面

六、总结

通过本文,我们完成了以下内容:

  1. ✅ Flutter 组件化设计实践
  2. ✅ CustomScrollView + Sliver 混合滚动布局
  3. ✅ 底部导航栏完整实现
  4. ✅ 常见问题及解决方案记录

项目源码:

https://atomgit.com/lbbxmx111/haromyos_day_four

欢迎交流:

如有疑问,欢迎在评论区留言讨论!


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

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

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

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

相关推荐
小龙报2 小时前
【SOLIDWORKS 练习题】草图专题:3.机械臂
笔记·单片机·嵌入式硬件·物联网·开源·硬件工程·材料工程
No Silver Bullet2 小时前
HarmonyOS NEXT开发进阶(二十三):多端原生App中通过WebView嵌套Web应用实现机制
前端·华为·harmonyos
万岳科技系统开发2 小时前
开源多商户商城系统设计思路平台型电商如何落地
开源
一起养小猫2 小时前
Flutter for OpenHarmony 实战:Container与Padding布局完全指南
android·flutter·harmonyos
zilikew2 小时前
Flutter框架跨平台鸿蒙开发——手工制作教程APP的开发流程
flutter·华为·harmonyos·鸿蒙
晚霞的不甘2 小时前
Flutter for OpenHarmony《淘淘购物》 分类页:从静态 UI 到动态交互的全面升级
flutter·ui·前端框架·交互·鸿蒙
kirk_wang2 小时前
Flutter艺术探索-Flutter列表性能优化:ListView.builder与itemExtent
flutter·移动开发·flutter教程·移动开发教程
Xxtaoaooo2 小时前
React Native 跨平台鸿蒙开发实战:与鸿蒙原子化服务(Atomic Service)融合
react native·react.js·harmonyos
Whisper_Sy11 小时前
Flutter for OpenHarmony移动数据使用监管助手App实战 - 网络状态实现
android·java·开发语言·javascript·网络·flutter·php