Gridly:Flutter × Harmony 6.0 构建卡片网格布局实战

前言

在移动应用和桌面应用的跨端开发中,界面布局的美观性和可用性直接影响用户体验。卡片网格布局作为一种常见的 UI 形式,能够将功能模块以清晰、整齐的方式呈现,同时支持图标、标题和统计信息的直观展示。本文将带你使用 Flutter × HarmonyOS 6.0 构建一个带阴影和圆角的卡片网格布局,实现跨端兼容的高质量界面。


在这里插入图片描述

背景

随着 HarmonyOS 生态的逐渐成熟,开发者越来越希望在同一套代码下实现手机、平板和 PC 的一致体验。而 Flutter 作为 Google 推出的跨平台 UI 框架,凭借其 一次编写、多端运行 的特性,成为 HarmonyOS 开发者的理想选择。

本文示例的核心需求是:

  1. 使用卡片(Card)展示功能模块。
  2. 卡片支持圆角和阴影效果。
  3. 每个卡片显示图标、标题及计数信息。
  4. 布局为网格形式,适配不同屏幕尺寸。

应用名称:Gridly —— 简单、直观、灵活的网格布局展示工具。


Flutter × Harmony 6.0 跨端开发介绍

Flutter 提供了丰富的 UI 组件库,能够快速实现美观的卡片布局。HarmonyOS 6.0 支持 HarmonyOS 能力的 Flutter 插件,让开发者可以直接在 Flutter 中调用分布式能力,实现多设备共享 UI 逻辑。

在本示例中,我们主要用到的 Flutter 核心特性:

  • GridView.builder:动态构建网格布局。
  • Card 组件:内置阴影、圆角和背景效果。
  • IconText:用于展示图标和文字信息。
  • ThemeData:适配系统主题颜色,实现统一风格。

HarmonyOS 6.0 下的 Flutter 环境可以直接渲染这些组件,无需针对不同设备做额外适配。
在这里插入图片描述


开发核心代码

在这里插入图片描述

下面是 Gridly 的核心布局实现:

/// 构建卡片网格布局
/// 使用Card组件创建带有阴影和圆角的网格项
/// 每个卡片包含图标、标题和计数信息
Widget _buildCardGrid(ThemeData theme) {
  final items = [
    {
      'icon': Icons.shopping_cart,
      'title': '购物',
      'count': 12,
      'color': Colors.pink
    },
    {
      'icon': Icons.favorite,
      'title': '收藏',
      'count': 8,
      'color': Colors.red
    },
    {
      'icon': Icons.history,
      'title': '历史',
      'count': 25,
      'color': Colors.orange
    },
    {
      'icon': Icons.download,
      'title': '下载',
      'count': 3,
      'color': Colors.green
    },
    {
      'icon': Icons.folder,
      'title': '文件',
      'count': 156,
      'color': Colors.blue
    },
    {
      'icon': Icons.image,
      'title': '图片',
      'count': 89,
      'color': Colors.purple
    },
  ];
  
  return Container(
    decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(12),
      color: theme.colorScheme.surfaceContainerHighest,
    ),
    padding: const EdgeInsets.all(8),
    child: GridView.builder(
      shrinkWrap: true,
      physics: const NeverScrollableScrollPhysics(),
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 3, // 每行显示3个卡片
        mainAxisSpacing: 8,
        crossAxisSpacing: 8,
        childAspectRatio: 1.0,
      ),
      itemCount: items.length,
      itemBuilder: (context, index) {
        final item = items[index];
        return Card(
          elevation: 2, // 阴影高度
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(8), // 圆角
          ),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Icon(
                item['icon'] as IconData,
                size: 32,
                color: item['color'] as Color,
              ),
              const SizedBox(height: 8),
              Text(
                item['title'] as String,
                style: theme.textTheme.bodySmall,
              ),
              const SizedBox(height: 4),
              Text(
                '${item['count']}',
                style: theme.textTheme.titleMedium?.copyWith(
                  fontWeight: FontWeight.bold,
                ),
              ),
            ],
          ),
        );
      },
    ),
  );
}

代码解析

  1. 数据定义
    items 列表保存了每个卡片的属性:图标(Icon)、标题(title)、计数(count)和颜色(color)。这种方式便于后续扩展或动态加载数据。

  2. 外层容器
    Container 设置圆角和背景颜色,保证网格整体视觉风格统一。

  3. GridView.builder

    • shrinkWrap: true:让 GridView 根据内容自适应高度。
    • NeverScrollableScrollPhysics:禁止滚动,适合嵌套在可滚动的父组件中。
    • SliverGridDelegateWithFixedCrossAxisCount:定义网格的列数、间距和比例。
  4. Card 组件

    • elevation 设置阴影高度,使卡片在视觉上浮起。
    • RoundedRectangleBorder 实现圆角效果。
    • 内部用 Column 布局,将图标、标题和计数垂直排列并居中。
  5. 样式适配
    ThemeData 提供统一的字体和颜色方案,使应用支持暗色/亮色主题切换。


在这里插入图片描述

代码解析(分段解析)

1. 数据定义部分

final items = [
  {
    'icon': Icons.shopping_cart,
    'title': '购物',
    'count': 12,
    'color': Colors.pink
  },
  {
    'icon': Icons.favorite,
    'title': '收藏',
    'count': 8,
    'color': Colors.red
  },
  ...
];

解析:

  • 这里使用了一个 List<Map<String, dynamic>> 来保存每个卡片的信息。

  • 每个 Map 包含:

    • icon:卡片图标。
    • title:卡片标题。
    • count:计数信息。
    • color:图标颜色。
  • 这种方式便于后续扩展,比如从接口动态加载数据,而无需修改布局逻辑。


2. 外层容器(Container)

return Container(
  decoration: BoxDecoration(
    borderRadius: BorderRadius.circular(12),
    color: theme.colorScheme.surfaceContainerHighest,
  ),
  padding: const EdgeInsets.all(8),

解析:

  • Container 用于包裹整个网格布局。

  • BoxDecoration 提供:

    • borderRadius:设置圆角,提升视觉美感。
    • color:背景色,使用 ThemeDatasurfaceContainerHighest 适配系统主题(亮/暗模式)。
  • padding 保证网格与容器边缘保持间距,让界面更整齐。


3. GridView 构建网格布局

child: GridView.builder(
  shrinkWrap: true,
  physics: const NeverScrollableScrollPhysics(),
  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 3,
    mainAxisSpacing: 8,
    crossAxisSpacing: 8,
    childAspectRatio: 1.0,
  ),
  itemCount: items.length,

解析:

  • GridView.builder:动态生成网格项,比 GridView.count 更灵活,适合数据量变化的场景。

  • shrinkWrap: true:让网格高度自适应内容,避免在嵌套可滚动组件时布局冲突。

  • NeverScrollableScrollPhysics():禁止 GridView 自身滚动,适合放在外层可滚动视图内。

  • SliverGridDelegateWithFixedCrossAxisCount

    • crossAxisCount:每行显示 3 个卡片。
    • mainAxisSpacing / crossAxisSpacing:主轴和横轴间距。
    • childAspectRatio:宽高比为 1,保证卡片是正方形。

4. Card 组件布局

return Card(
  elevation: 2,
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(8),
  ),
  child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
      Icon(
        item['icon'] as IconData,
        size: 32,
        color: item['color'] as Color,
      ),
      const SizedBox(height: 8),
      Text(
        item['title'] as String,
        style: theme.textTheme.bodySmall,
      ),
      const SizedBox(height: 4),
      Text(
        '${item['count']}',
        style: theme.textTheme.titleMedium?.copyWith(
          fontWeight: FontWeight.bold,
        ),
      ),
    ],
  ),
);

解析:

  • Card:自带阴影效果,提升卡片层次感。

    • elevation:阴影高度,值越大阴影越明显。
    • shape:使用 RoundedRectangleBorder 实现圆角。
  • 内部 Column

    • mainAxisAlignment: MainAxisAlignment.center:垂直居中排列内容。
    • Icon:显示功能图标,颜色和大小可配置。
    • Text(标题):使用主题字体,保证和系统风格一致。
    • Text(计数):加粗显示数量信息,使视觉重点突出。
  • SizedBox 用于设置元素间距,使布局整齐美观。


5. 样式适配

color: theme.colorScheme.surfaceContainerHighest
style: theme.textTheme.bodySmall
style: theme.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold)

解析:

  • 使用 ThemeDatacolorSchemetextTheme,实现暗色/亮色模式自适应。
  • copyWith 可在继承主题样式基础上修改局部属性,比如加粗或调整颜色,保证整体风格一致。

心得

在 HarmonyOS 6.0 下使用 Flutter 开发的过程中,我有以下几点体会:

  1. 跨端 UI 一致性
    Flutter 的 Widget 系统能在手机、平板、PC 上保持一致的布局,不需要重复适配。

  2. 可扩展性强
    通过配置化的 items 列表,未来可以轻松增加新功能卡片,或从服务器动态加载数据。

  3. Material 组件优势
    Card、GridView 等组件自带阴影、圆角和响应式布局,使 UI 开发效率显著提升。

  4. HarmonyOS 能力整合
    通过 Flutter 插件调用 HarmonyOS API,可以实现分布式 UI、数据同步和多端共享,进一步提升应用体验。


总结

本文介绍了如何在 Flutter × HarmonyOS 6.0 环境下构建卡片网格布局,实现带有阴影、圆角、图标和计数信息的模块化界面。通过 GridView.builderCard 组件结合,可以轻松创建灵活、可扩展、跨端一致的 UI。

Gridly 的实现展示了 Flutter 在 HarmonyOS 上的开发优势,也为未来构建多端统一的应用提供了参考模板。只需修改数据源或样式,就能快速生成功能丰富、界面美观的网格布局。

通过本次实践,我们使用 Flutter × HarmonyOS 6.0 成功构建了一个灵活、美观且跨端一致的卡片网格布局。借助 GridView.builder 和 Card 组件,我们不仅实现了图标、标题和计数信息的直观展示,还通过圆角和阴影增强了界面层次感。整个布局高度可扩展、易维护,同时兼顾手机、平板和 PC 的适配需求。此次开发体验充分体现了 Flutter 在跨端 UI 开发中的高效与便利,也为未来构建模块化、可动态扩展的应用界面提供了可靠的参考模板。

Logo

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

更多推荐