本文参考Flutter鸿蒙开发指南(五):实现首页基础布局-CSDN博客

本文记录操作过程以及遇到的问题

在上一节中,我们已完成电商App底部Tab栏的实现,成功搭建了App的基础框架。这一节,我们将聚焦首页开发,逐步实现轮播图、分类、推荐、爆款、商品列表等核心模块,完成首页基础布局的搭建,让App首页具备完整的可视化效果。

一、项目结构搭建

首页布局由多个独立子组件组成,为了保证项目结构清晰、便于后续维护和扩展,我们先在指定目录下新建所需组件文件。

1.1 新建项目组件

在lib/components下新建Home文件夹,再分别新建以下文件:

  • HmSlider.dart文件,用于实现首页顶部轮播图组件
  • HmCategory.dart文件,用于实现首页横向滚动分类组件
  • HmSuggestion.dart文件,用于实现首页推荐区域组件
  • HmHot.dart文件,用于实现首页爆款推荐组件
  • HmMoreList.dart文件,用于实现首页商品无限滚动列表组件

【新手提示】:在Android Studio或VS Code中,新建Dart文件后,输入快捷指令stful,即可一键生成StatefulWidget组件的模板代码(包含组件类和对应的状态类),无需手动编写基础结构,提升开发效率。

1.2 初始化组件代码

HmCatrgory.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 const Placeholder();
  }
}

HmHot.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 const Placeholder();
  }
}

HmMoreList.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 const Placeholder();
  }
}

HmSlider.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();
  }
}

HmSuggestion.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 const Placeholder();
  }
}

二、编写组件对应代码

2.1 轮播图组件代码

HmSlider.dart代码

轮播图是电商App首页的核心模块之一,此处我们先实现基础的轮播图容器(蓝色背景+文字提示),后续可扩展为真实的图片轮播效果,代码如下:

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 Container(
        color: Colors.blue,
        height: 300,
        alignment: Alignment.center,
        child:
            Text('轮播图', style: TextStyle(color: Colors.white, fontSize: 20)));
  }
}

整合到首页

修改Home/index.dart代码

轮播图组件编写完成后,需要将其导入到首页核心文件中,使用CustomScrollView实现滚动布局(适配后续更多组件的滚动需求),代码如下:

import 'package:flutter/cupertino.dart';
import 'package:xiuhu_mall/components/Home/HmSlider.dart';

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

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

class _HomeViewState extends State<HomeView> {
  //获取滚动容器的内容

  List<Widget> _getScrollChildren() {
    return [
      //包裹普通widget的sliver家族的组件内容
      SliverToBoxAdapter(child: HmSlider()),//轮播图组件
    ];
  }

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

效果展示

2.2 分类组件代码

HmCategory.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) {
    //返回一个横向滚动的组件,但是得设置高度。但是ListView自身不能设置高度.能设置高度的只有Container和SizeBox
    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: TextStyle(color: Colors.white)),
              margin: EdgeInsets.symmetric(horizontal: 10),
            );
          }),
    );
  }
}

报错以及解决方案

【报错内容】:Container同时设置了color和decoration导致的冲突。

【报错原因】:Flutter中,Container的color属性是decoration(装饰)的简写形式,两者不能同时设置,否则会出现语法冲突,编译器无法识别优先级。

【解决方案】:将color属性移到decoration的BoxDecoration中,同时我们优化代码,添加点击选中效果(选中时改变背景色和文字样式),修改后的完整HmCategory.dart代码如下:

import 'package:flutter/material.dart';

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

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

class _HmCategoryState extends State<HmCategory> {
  int _selectedIndex = -1;

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 100,
      child: ListView.builder(
        scrollDirection: Axis.horizontal,
        itemCount: 10,
        padding: const EdgeInsets.symmetric(horizontal: 16),
        itemBuilder: (BuildContext context, int index) {
          bool isSelected = _selectedIndex == index;

          return GestureDetector(
            onTap: () {
              setState(() => _selectedIndex = index);
              print("点击了分类$index");
            },
            child: Container(
              alignment: Alignment.center,
              width: 80,
              height: 80,
              // 把color移到decoration里,解决冲突
              decoration: BoxDecoration(
                color: isSelected ? Theme.of(context).primaryColor : Colors.grey[100],
                borderRadius: BorderRadius.circular(12),
                boxShadow: [
                  BoxShadow(
                    color: Colors.black12,
                    blurRadius: 3,
                    offset: const Offset(0, 2),
                  )
                ],
              ),
              margin: const EdgeInsets.symmetric(horizontal: 8),
              child: Text(
                "分类$index",
                style: TextStyle(
                  color: isSelected ? Colors.white : Colors.black87,
                  fontSize: 16,
                  fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}

更新首页代码

修改Home/index.dart代码

import 'package:flutter/material.dart';
import 'package:xiuhu_mall/components/Home/HmSlider.dart';
import 'package:xiuhu_mall/components/Home/HmCategory.dart';


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

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

class _HomeViewState extends State<HomeView> {
  @override
  Widget build(BuildContext context) {
    // 用SingleChildScrollView实现页面滚动,包裹Column放轮播图+分类
    return SingleChildScrollView(
      child: Column(
        children: [
          // 1. 轮播图组件
          HmSlider(),
          // 2. 分类组件(加个上下间距更美观)
          const SizedBox(height: 10),
          HmCategory(),
          // 可继续添加其他组件
        ],
      ),
    );
  }
}

效果

2.3 推荐组件代码

HmSuggestion.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 Container(
        color: Colors.blue,
        alignment: Alignment.center,
        height: 300,
        child: Text(
          "推荐",
          style: TextStyle(color: Colors.white),
        ));
  }
}

更新首页代码

修改Home/index.dart代码:

导入推荐组件,优化首页布局,添加全局左右内边距,调整组件间距

import 'package:flutter/material.dart';
import 'package:xiuhu_mall/components/Home/HmSlider.dart';
import 'package:xiuhu_mall/components/Home/HmCategory.dart';
import 'package:xiuhu_mall/components/Home/HmSuggestion.dart';

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

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

class _HomeViewState extends State<HomeView> {
  @override
  Widget build(BuildContext context) {
    // 用SingleChildScrollView实现页面滚动,包裹Column放轮播图+分类+推荐
    return SingleChildScrollView(
      // 2. 给整个滚动区域加左右内边距,避免组件贴边
      padding: const EdgeInsets.symmetric(horizontal: 16),
      child: Column(
        children: [
          // 1. 轮播图组件
          HmSlider(),
          // 2. 分类组件
          const SizedBox(height: 16),
          HmCategory(),
          // 3. 补全推荐组件(加上间距,和分类组件呼应)
          const SizedBox(height: 16),
          HmSuggestion(),
          // 4. 底部加间距,避免推荐组件贴底(和底部Tab栏留出空隙)
          const SizedBox(height: 20),
        ],
      ),
    );
  }
}

效果

2.4 爆款推荐组件代码

HmHot.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: Text('爆款推荐', style: TextStyle(color: Colors.white)),
    );
  }
}

优化推荐组件

为了让推荐组件和爆款组件风格统一,给推荐组件添加左右内边距,修改后的HmSuggestion.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: EdgeInsets.symmetric(horizontal: 10),
        child: Container(
            color: Colors.blue,
            alignment: Alignment.center,
            height: 300,
            child: Text(
              "推荐",
              style: TextStyle(color: Colors.white),
            )));
  }
}

更新首页代码

将首页滚动布局改回CustomScrollView(适配后续无限滚动列表),导入爆款组件,用Flex+Expanded实现两个爆款容器横向均分,修改后的Home/index.dart代码如下:

import 'package:flutter/cupertino.dart';
import 'package:xiuhu_mall/components/Home/HmCategory.dart';
import 'package:xiuhu_mall/components/Home/HmHot.dart';
import 'package:xiuhu_mall/components/Home/HmSlider.dart';
import 'package:xiuhu_mall/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 [
      //包裹普通widget的sliver家族的组件内容
      SliverToBoxAdapter(child: HmSlider()), //轮播图组件
      //放置分类组件
      SliverToBoxAdapter(child: SizedBox(height: 10)),
      //SliverGrid SliverList指南纵向排列
      SliverToBoxAdapter(child: HmCategory()), //分类组件
      SliverToBoxAdapter(child: SizedBox(height: 10)),
      SliverToBoxAdapter(child: HmSuggestion()), //推荐组件
      SliverToBoxAdapter(child: SizedBox(height: 10)),

      //Flex和Expanded配合起来可以均分比例
      SliverToBoxAdapter(
        child: Padding(
            padding: EdgeInsets.symmetric(horizontal: 10),
            child: Flex(
              direction: Axis.horizontal,
              children: [
                Expanded(child: HmHot()),
                SizedBox(
                  width: 10,
                ),
                Expanded(child: HmHot()),
              ],
            )),
      ),
    ];
  }

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

效果

2.5 商品无限滚动列表组件

HmMoreList.dart代码

商品列表组件用于展示大量商品,实现无限滚动效果(此处用SliverGrid实现两列网格布局,模拟商品列表),代码如下:

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) {
    //必须是Sliver家族的组件
    return SliverGrid.builder(gridDelegate:
    //网格是两列
    SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
        mainAxisSpacing: 10,
        crossAxisSpacing: 10),
        itemBuilder: (BuildContext context, int index) {
          return Container(
            child: Text("商品", style: TextStyle(color: Colors.white),),
            color: Colors.blue,
            alignment: Alignment.center,
          );
        });
  }
}

更新首页代码

导入商品列表组件,添加间距,将其整合到首页底部,修改后的Home/index.dart代码如下:

import 'package:flutter/cupertino.dart';
import 'package:xiuhu_mall/components/Home/HmCategory.dart';
import 'package:xiuhu_mall/components/Home/HmHot.dart';
import 'package:xiuhu_mall/components/Home/HmMoreList.dart';
import 'package:xiuhu_mall/components/Home/HmSlider.dart';
import 'package:xiuhu_mall/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 [
      //包裹普通widget的sliver家族的组件内容
      SliverToBoxAdapter(child: HmSlider()), //轮播图组件
      //放置分类组件
      SliverToBoxAdapter(child: SizedBox(height: 10)),
      //SliverGrid SliverList指南纵向排列
      SliverToBoxAdapter(child: HmCategory()), //分类组件
      SliverToBoxAdapter(child: SizedBox(height: 10)),
      SliverToBoxAdapter(child: HmSuggestion()), //推荐组件
      SliverToBoxAdapter(child: SizedBox(height: 10)),
 
      //Flex和Expanded配合起来可以均分比例
      SliverToBoxAdapter(
        child: Padding(
            padding: EdgeInsets.symmetric(horizontal: 10),
            child: Flex(
              direction: Axis.horizontal,
              children: [
                Expanded(child: HmHot()),
                SizedBox(
                  width: 10,
                ),
                Expanded(child: HmHot()),
              ],
            )),
      ),
      SliverToBoxAdapter(child: SizedBox(height: 10)),
      HmMorelist(),//无限滚动列表
    ];
  }
 
  @override
  Widget build(BuildContext context) {
    //CustomScrollview要求:必须是sliver家族的内容
    return CustomScrollView(slivers: _getScrollChildren());
  }
}

效果

三、Git上传代码

完成开发并测试通过后,使用Git提交代码,保存当前开发进度,执行以下命令(依次在控制台输入):

git add .
git commit -m "完成首页基础布局"
git push

【新手提示】:若执行git push时报错,需先关联远程仓库(执行git remote add origin 远程仓库地址),再执行推送命令;若忘记远程仓库地址,可在GitHub、Gitee等平台查看对应仓库的地址。

四、总结

本次开发我们基于上一节实现的底部Tab栏,完成了电商App首页基础布局的搭建,核心收获如下:

  1. 组件化拆分:将首页拆分为轮播图、分类、推荐、爆款、商品列表5个独立子组件,让项目结构更清晰,便于后续维护和功能扩展。​
  2. 布局技能提升:熟练使用CustomScrollView、SingleChildScrollView实现页面滚动,掌握SliverToBoxAdapter、SliverGrid的使用方法,学会用Flex+Expanded实现组件横向均分。​
  3. 报错解决能力:遇到Container的color和decoration冲突问题,通过将color整合到decoration中成功解决,积累了基础的Flutter语法报错解决经验。​
  4. 细节优化技巧:通过添加内边距、间距、圆角、阴影,提升页面美观度;通过点击事件实现分类选中效果,增强页面交互性。

本次实现的首页布局为基础版本,后续可进行进一步优化:将占位的蓝色容器替换为真实的图片、完善商品列表的数据渲染、实现轮播图的自动切换和点击跳转、优化组件的响应式布局(适配不同屏幕尺寸)等。

最后

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

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐