Flutter 鸿蒙开发实践:利用三方库构建跨端极简单位转换器

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

1. 前言

对于刚入门的 \\ 鸿蒙(HarmonyOS)\\ 开发者,掌握数据流转和 UI 交互是核心能力。Flutter 作为跨端应用开发框架,能高效实现一套代码同时适配鸿蒙、Android、iOS 等多端系统,大幅降低开发与维护成本。

本文将以极简单位转换器为实战案例,手把手带你完成:

  • Flutter 集成 font\_awesome\_flutter 图标库

  • 使用 intl 实现高精度数值格式化

  • 在无真机环境下,通过 HarmonyOS Next 虚拟机开发调试

  • 解决鸿蒙编译常见配置报错(bundleName 不匹配、Schema 校验失败)


2. 核心关键词

  • Flutter:跨平台 UI 框架,一套代码多端运行

  • font_awesome_flutter:提供精美矢量图标,提升界面视觉效果

  • intl:数字格式化、小数位保留、国际化处理

  • HarmonyOS Next:鸿蒙下一代系统,支持 Flutter 跨端运行

  • 单位转换:长度(厘米 ↔ 英寸)、重量(公斤 ↔ 磅)


3. 环境准备

3.1 开发环境

  • Flutter SDK(建议 3.10.0 及以上)

  • DevEco Studio(鸿蒙开发 IDE)

  • HarmonyOS Next 虚拟机

  • 已配置 Flutter 鸿蒙编译环境

3.2 项目依赖配置

在项目根目录 pubspec\.yaml 中添加:

dependencies:
  flutter:
    sdk: flutter
  # 精美图标库
  font_awesome_flutter: ^10.7.0
  # 数字格式化
  intl: ^0.19.0

flutter:
  uses-material-design: true

执行安装命令:

flutter pub get

4. 项目设计

4.1 功能清单

  • 长度单位转换:厘米 ↔ 英寸

  • 重量单位转换:公斤 ↔ 磅

  • 输入数值校验

  • 结果保留两位小数

  • 鸿蒙简约风格 UI

  • 支持虚拟机 / 真机运行

4.2 界面结构

  • 顶部标题栏(带图标)

  • 转换类型切换(长度 / 重量)

  • 数字输入框

  • 转换按钮

  • 结果展示区域


5. 完整代码实现

5.1 单位转换工具类

新建路径:lib/utils/unit\_converter\.dart

/// 通用单位转换工具类
class UnitConverter {
  /// 长度:厘米 → 英寸
  static double cmToInch(double cm) {
    return cm * 0.393701;
  }

  /// 长度:英寸 → 厘米
  static double inchToCm(double inch) {
    return inch * 2.54;
  }

  /// 重量:公斤 → 磅
  static double kgToLb(double kg) {
    return kg * 2.20462;
  }

  /// 重量:磅 → 公斤
  static double lbToKg(double lb) {
    return lb * 0.453592;
  }
}

5.2 主页面代码

替换文件:lib/main\.dart

import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'utils/unit_converter.dart';

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

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter 鸿蒙单位转换器',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: const HomePage(),
    );
  }
}

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

  
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // 转换类型
  enum ConvertType { length, weight }
  ConvertType _currentType = ConvertType.length;

  // 输入与结果
  final TextEditingController _inputController = TextEditingController();
  String _result = '请输入数字并转换';

  // 保留两位小数
  final NumberFormat _format = NumberFormat('#0.00');

  // 转换逻辑
  void _doConvert() {
    String inputText = _inputController.text.trim();
    if (inputText.isEmpty) {
      setState(() => _result = '请输入有效数字');
      return;
    }

    double? input = double.tryParse(inputText);
    if (input == null) {
      setState(() => _result = '输入格式不正确');
      return;
    }

    double output;
    String unitFrom, unitTo;

    if (_currentType == ConvertType.length) {
      output = UnitConverter.cmToInch(input);
      unitFrom = '厘米';
      unitTo = '英寸';
    } else {
      output = UnitConverter.kgToLb(input);
      unitFrom = '公斤';
      unitTo = '磅';
    }

    setState(() {
      _result = '$input $unitFrom = ${_format.format(output)} $unitTo';
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: const FaIcon(FontAwesomeIcons.rulerCombined),
        title: const Text('极简单位转换器'),
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            // 类型切换
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                _typeItem(
                  icon: FontAwesomeIcons.ruler,
                  label: '长度',
                  type: ConvertType.length,
                ),
                const SizedBox(width: 40),
                _typeItem(
                  icon: FontAwesomeIcons.weightScale,
                  label: '重量',
                  type: ConvertType.weight,
                ),
              ],
            ),
            const SizedBox(height: 30),

            // 输入框
            TextField(
              controller: _inputController,
              keyboardType: const TextInputType.numberWithOptions(decimal: true),
              decoration: const InputDecoration(
                labelText: '请输入数值',
                border: OutlineInputBorder(),
                prefixIcon: FaIcon(FontAwesomeIcons.calculator),
              ),
            ),
            const SizedBox(height: 20),

            // 转换按钮
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                onPressed: _doConvert,
                child: const Padding(
                  padding: EdgeInsets.all(14),
                  child: Text('开始转换', style: TextStyle(fontSize: 16)),
                ),
              ),
            ),
            const SizedBox(height: 30),

            // 结果展示
            Container(
              width: double.infinity,
              padding: const EdgeInsets.all(16),
              decoration: BoxDecoration(
                color: Colors.grey.shade100,
                borderRadius: BorderRadius.circular(8),
              ),
              child: Text(
                _result,
                style: const TextStyle(fontSize: 18),
                textAlign: TextAlign.center,
              ),
            ),
          ],
        ),
      ),
    );
  }

  // 类型选择组件
  Widget _typeItem({
    required IconData icon,
    required String label,
    required ConvertType type,
  }) {
    bool isSelected = _currentType == type;
    return GestureDetector(
      onTap: () => setState(() => _currentType = type),
      child: Column(
        children: [
          FaIcon(
            icon,
            size: 36,
            color: isSelected ? Colors.blue : Colors.grey,
          ),
          const SizedBox(height: 6),
          Text(
            label,
            style: TextStyle(
              fontSize: 15,
              color: isSelected ? Colors.blue : Colors.grey,
              fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
            ),
          ),
        ],
      ),
    );
  }
}

6. 鸿蒙运行与配置

6.1 运行项目

flutter run -d harmony

6.2 必须配置:app.json5

ohos/ 目录下创建 app\.json5

{
  "app": {
    "bundleName": "com.example.flutter_harmonyos4",
    "vendor": "example",
    "versionCode": 1,
    "versionName": "1.0.0"
  }
}

6.3 常见报错解决

报错:bundleName 不匹配

  • 原因:签名配置与包名不一致

  • 解决:删除 build\-profile\.json5 中旧 signingConfigs,Clean → Rebuild

报错:Schema validate failed

  • 原因:module\.json5 不能写 appbundleName

  • 解决:保持 module\.json5 为默认结构


7. 扩展功能方向

  • 增加温度、面积、体积、时间等单位

  • 支持反向转换

  • 添加历史记录列表

  • 适配鸿蒙深色模式

  • 支持一键复制结果

  • 增加输入清空按钮


8. 总结

本文通过极简单位转换器完整案例,覆盖了 Flutter 鸿蒙开发的核心知识点:

  • 三方库(图标、数字格式化)集成

  • 鸿蒙项目结构与配置规范

  • 数据处理、UI 交互、状态管理

  • 虚拟机调试 + 常见报错解决方案

运行截图:
在这里插入图片描述

Logo

一站式 AI 云服务平台

更多推荐