一、需求分析

以常见的电商平台举例,如淘宝、京东、拼多多都有底部导航栏。本章节要实现的内容就是实现四个底部导航栏:首页、分类、购物车、我的。

淘宝

京东

拼多多

二、使用git回退代码

在Flutter鸿蒙开发指南(三)使用dio库实现网络请求这一节中,我们完成了网络请求。但是这个和我们要做的电商App所需接口不符合。所以我们要对代码进行回撤。

俗话说:“世上没有后悔药“。

但是在代码的世界是有后悔药的,我们要使用Git的操作进行回撤退就相当于后悔药了。

使用Git回退会将工作目录和暂存区完全恢复到上一次提交的状态,所有未提交的更改都将永久丢失,所以大家需要根据情况而用。我这里是完全不需要上次的代码了,所以直接全部丢失也无所谓。

git reset --hard HEAD

当执行完上面的Git命令,你会发现代码变成了我们第一次提交“搭建基础路由和组件”时候的状态(变成了我们第一次提交时候的代码)

三、实现主页Tab栏实现

首先将文件夹中的八张图片拷贝,分别是底部导航栏的选中和未选中。复制粘贴到项目中的"assets"文件夹中。大家可以在我的代码仓库就获取这八张图片,顺便给我点个Star。

青商城 - AtomGit | GitCodehttps://atomgit.com/Deng666/shangcheng

按住Ctrl+/解开这里的注释

改成如图所示,并且点击右上角的Pub get,如果不会改就复制粘贴以下代码:

flutter:
  uses-material-design: true

  # To add assets to your application, add an assets section, like this:
  assets:
    - lib/assets/


然后开始在lib/Main/index.dart开始编写代码

3.1 第一次编写代码

lib/Main/index.dart,第一次编写的代码如下,图标显示不正常。这个时候可能有三种解决方法:

(1)再次运行项目即可

(2)pubspec.yaml未执行Pub get

(3)图片的路径错误,修改好正确路径即可

import 'package:flutter/material.dart';

/*
 * @author:幻影
 * @date:2025-1-25
 *[Tabs:首页]
 */

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

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  //定义数据 根据数据进行渲染4个导航 List<Map>:key value <String,String>是泛型
  //一般应用程序的导航是固定的
  final List<Map<String, String>> _tabList = [
    {
      "icon": "lib/assets/ic_public_home_normal.png", //未选中
      "active_icon": "lib/assets/ic_public_home_active.png",//选中
      "text": "首页",
    },
    {
      "icon": "lib/assets/ic_public_pro_normal.png", //未选中
      "active_icon": "lib/assets/ic_public_pro_active.png",//选中
      "text": "分类",
    },
    {
      "icon": "lib/assets/ic_public_cart_normal.png", //未选中
      "active_icon": "lib/assets/ic_public_cart_active.png",//选中
      "text": "购物车",
    },
    {
      "icon": "lib/assets/ic_public_my_normal.png", //未选中
      "active_icon": "lib/assets/ic_public_my_active.png",//选中
      "text": "我的",
    },
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text("主页"),
      ),
    );
  }
}

3.2 第二次编写代码

此时,底部导航栏的Tab和文字都显示正常。但是当你点击的时候,你会发现无法点击。原因是缺少了关键的当前选中索引管理,我们通过"currentIndex"状态来跟踪选中的标签,并且添加onTap回调来处理切换即可。(请看第三次编写代码)

import 'package:flutter/material.dart';

/*
 * @author:幻影
 * @date:2025-1-25
 *[Tabs:首页]
 */

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

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  //定义数据 根据数据进行渲染4个导航 List<Map>:key value <String,String>是泛型
  //一般应用程序的导航是固定的
  final List<Map<String, String>> _tabList = [
    {
      "icon": "lib/assets/ic_public_home_normal.png", //未选中
      "active_icon": "lib/assets/ic_public_home_active.png", //选中
      "text": "首页",
    },
    {
      "icon": "lib/assets/ic_public_pro_normal.png", //未选中
      "active_icon": "lib/assets/ic_public_pro_active.png", //选中
      "text": "分类",
    },
    {
      "icon": "lib/assets/ic_public_cart_normal.png", //未选中
      "active_icon": "lib/assets/ic_public_cart_active.png", //选中
      "text": "购物车",
    },
    {
      "icon": "lib/assets/ic_public_my_normal.png", //未选中
      "active_icon": "lib/assets/ic_public_my_active.png", //选中
      "text": "我的",
    },
  ];

  //返回底部渲染的四个分类
  List<BottomNavigationBarItem> _getTabBarWidget() {
    return List.generate(_tabList.length, (int index) {
      return BottomNavigationBarItem(
        icon: Image.asset(
          _tabList[index]["icon"]!, //正常显示图标
          width: 30,
          height: 30,
        ),
        activeIcon: Image.asset(
          _tabList[index]["active_icon"]!,
          width: 30,
          height: 30,
        ),
        label: _tabList[index]["text"],
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text("主页"),
      ),
      bottomNavigationBar: BottomNavigationBar(items: _getTabBarWidget(),type: BottomNavigationBarType.fixed)
    );
  }
}

3.3 第三次编写代码

第三次编码在第二次的编码基础上增加了以下四点:

(1)独立模块化:四个页面(首页、分类、购物车、我的)拆分成了独立组件,代码结构清晰,便于维护和团队协作。

(2)IndexedStack保持状态:切换页面时保留滚动位置和表单数据,提升用户体验和性能

(3)SafeArea安全适配:自动避让刘海屏和系统UI区域,确保内容显示完整不被遮挡

(4)导航栏样式优化:统一选中与未选中颜色,增强视觉效果和美观度。

新建以下四个文件夹以及代码:Cart文件夹下的index.dart,Category文件夹下的index.dart,Home文件夹下的index.dart,Mine文件夹下的index.dart。

lib/pages/Main/index.dart代码

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:qing_mall/pages/Cart/index.dart';
import 'package:qing_mall/pages/Category/index.dart';
import 'package:qing_mall/pages/Home/home.dart';
import 'package:qing_mall/pages/Mine/mine.dart';

/*
 * @author:幻影
 * @date:2025-1-25
 *[Tabs:首页]
 */

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

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  //定义数据 根据数据进行渲染4个导航 List<Map>:key value <String,String>是泛型
  //一般应用程序的导航是固定的
  final List<Map<String, String>> _tabList = [
    {
      "icon": "lib/assets/ic_public_home_normal.png", //未选中
      "active_icon": "lib/assets/ic_public_home_active.png", //选中
      "text": "首页",
    },
    {
      "icon": "lib/assets/ic_public_pro_normal.png", //未选中
      "active_icon": "lib/assets/ic_public_pro_active.png", //选中
      "text": "分类",
    },
    {
      "icon": "lib/assets/ic_public_cart_normal.png", //未选中
      "active_icon": "lib/assets/ic_public_cart_active.png", //选中
      "text": "购物车",
    },
    {
      "icon": "lib/assets/ic_public_my_normal.png", //未选中
      "active_icon": "lib/assets/ic_public_my_active.png", //选中
      "text": "我的",
    },
  ];
  int _currentIndex = 0;

  //返回底部渲染的四个分类
  List<BottomNavigationBarItem> _getTabBarWidget() {
    return List.generate(_tabList.length, (int index) {
      return BottomNavigationBarItem(
        icon: Image.asset(
          _tabList[index]["icon"]!, //正常显示图标
          width: 30,
          height: 30,
        ),
        activeIcon: Image.asset(
          _tabList[index]["active_icon"]!,
          width: 30,
          height: 30,
        ),
        label: _tabList[index]["text"],
      );
    });
  }

  List<Widget> _getChildren() {
    return [HomeView(), CategoryView(), CartView(), MineView()];
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        //SafeArea会避开安全区组件
        body: SafeArea(
            child: IndexedStack(
          index: _currentIndex,
          children: _getChildren(), //放置四个组件
        )),
        bottomNavigationBar: BottomNavigationBar(
          showUnselectedLabels: true,
          unselectedItemColor: Colors.black,
          selectedItemColor: Colors.black,
          onTap: (int index) {
            //index就是当前点击的索引
            _currentIndex = index;
            setState(() {});
          },
          items: _getTabBarWidget(),
          type: BottomNavigationBarType.fixed,
          currentIndex: _currentIndex, //选中下标
        ));
  }
}

lib/pages/Cart/index.dart代码

import 'package:flutter/cupertino.dart';

//View结尾表示不是页面,Page结尾一般才是页面
class CartView extends StatefulWidget {
  const CartView({super.key});

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

class _CartViewState extends State<CartView> {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text("购物车"),
    );
  }
}

lib/pages/Category/index.dart代码

import 'package:flutter/cupertino.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 Center(
      child: Text("分类"),
    );
  }
}

lib/pages/Home/index.dart代码

import 'package:flutter/cupertino.dart';

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

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

class _CartViewState extends State<HomeView> {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text("首页"),
    );
  }
}

lib/pages/Mine/index.dart代码

import 'package:flutter/cupertino.dart';

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

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

class _CartViewState extends State<HomeView> {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text("首页"),
    );
  }
}

提交代码:

3.4 运行效果

最终的运行效果是点击底部导航栏对应的Tab显示对应的内容,比如点击我的就显示Mine/index.dart代码中的内容,点击购物车就显示Cart/index.dart代码中的的内容

安卓端:

鸿蒙端:

感谢您的观看,如果本篇文章对你有帮助,请你点个赞支持一下~您的支持就是我的动力。

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

Logo

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

更多推荐