【maaath】 Flutter for OpenHarmony 实战:电池优化应用开发指南

Flutter for OpenHarmony 实战:电池优化应用开发指南

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

作者:maaath


前言

Flutter 作为 Google 推出的跨平台 UI 框架,凭借其高性能、热重载和丰富的组件生态,已经成为移动端跨平台开发的首选方案之一。而 OpenHarmony 作为国产操作系统,正在积极拥抱跨平台开发框架。Flutter for OpenHarmony 的出现,让开发者能够使用同一套代码同时开发 Android、iOS 和 OpenHarmony 应用,大大提升了开发效率。

本文将通过一个实际的电池优化应用案例,详细讲解如何在 Flutter 项目中适配 OpenHarmony 平台,实现跨平台开发。项目中涉及的网络请求、本地存储等核心功能均采用 Flutter 官方推荐的实现方式,确保代码的可移植性和可维护性。

一、项目概述

本文要开发的是一个功能完善的电池优化应用,主要功能包括:

  • 实时显示电池电量、温度、电压等关键信息
  • 展示电池使用历史曲线
  • 功耗应用排行榜
  • 后台进程管理与优化
  • 省电模式设置

该项目采用 Flutter 实现 UI 界面,通过平台通道(Platform Channel)调用 OpenHarmony 原生能力获取电池数据。这种架构设计既保证了 Flutter 的跨平台优势,又能够充分发挥 OpenHarmony 的系统能力。

二、项目结构设计

一个良好的项目结构是代码可维护性的基础。本项目采用分层架构设计,将界面层、业务层和数据层分离:

复制代码
lib/
├── main.dart                    # 应用入口
├── model/                       # 数据模型层
│   └── battery_model.dart       # 电池相关数据模型
├── service/                     # 业务服务层
│   └── battery_service.dart     # 电池数据服务
├── pages/                       # 页面层
│   └── battery_page.dart       # 电池页面
├── components/                  # 组件层
│   ├── battery_circle_progress.dart  # 电量圆环组件
│   ├── battery_indicators.dart       # 电池指标卡片
│   ├── battery_history.dart          # 历史记录组件
│   ├── process_manager.dart          # 进程管理组件
│   └── common_components.dart        # 通用组件
└── utils/                       # 工具层
    └── battery_utils.dart       # 电池工具函数

这种分层设计的优势在于:各层职责清晰,便于单元测试;上层依赖下层,依赖关系明确;当需要更换底层实现时,对上层代码影响最小。

三、核心代码实现

3.1 数据模型层

数据模型是应用的基础数据结构,定义了电池信息的统一格式。良好的模型设计应该具备以下特点:类型安全、不可变性(对于纯数据类)以及与后端数据结构的一致性。

dart 复制代码
// lib/model/battery_model.dart

// 电池信息数据模型
class BatteryInfo {
  final int level;
  final String chargingStatus;
  final String health;
  final double temperature;
  final int voltage;
  final int currentNow;
  final int remainingEnergy;
  final int totalEnergy;

  BatteryInfo({
    required this.level,
    required this.chargingStatus,
    required this.health,
    required this.temperature,
    required this.voltage,
    required this.currentNow,
    required this.remainingEnergy,
    required this.totalEnergy,
  });

  // 工厂方法:从 JSON 创建对象
  factory BatteryInfo.fromJson(Map<String, dynamic> json) {
    return BatteryInfo(
      level: json['level'] as int,
      chargingStatus: json['chargingStatus'] as String,
      health: json['health'] as String,
      temperature: (json['temperature'] as num).toDouble(),
      voltage: json['voltage'] as int,
      currentNow: json['currentNow'] as int,
      remainingEnergy: json['remainingEnergy'] as int,
      totalEnergy: json['totalEnergy'] as int,
    );
  }

  // 转换为 JSON
  Map<String, dynamic> toJson() {
    return {
      'level': level,
      'chargingStatus': chargingStatus,
      'health': health,
      'temperature': temperature,
      'voltage': voltage,
      'currentNow': currentNow,
      'remainingEnergy': remainingEnergy,
      'totalEnergy': totalEnergy,
    };
  }
}

// 功耗排行数据模型
class PowerConsumptionInfo {
  final String appName;
  final String packageName;
  final int consumptionLevel;
  final double powerConsumptionMah;

  PowerConsumptionInfo({
    required this.appName,
    required this.packageName,
    required this.consumptionLevel,
    required this.powerConsumptionMah,
  });
}

// 进程项数据模型
class ProcessItem {
  final String appName;
  final String packageName;
  final double memoryUsage;
  final double cpuUsage;
  final bool isHighConsumption;

  ProcessItem({
    required this.appName,
    required this.packageName,
    required this.memoryUsage,
    required this.cpuUsage,
    required this.isHighConsumption,
  });
}

// 历史记录数据模型
class HistoryData {
  final DateTime timestamp;
  final int level;
  final bool isCharging;

  HistoryData({
    required this.timestamp,
    required this.level,
    required this.isCharging,
  });
}

上述模型设计采用了不可变(Immutable)模式,所有字段均为 final,通过构造函数初始化。这种设计的好处是:线程安全、无隐式修改、便于状态管理和调试。当需要修改对象时,创建新的实例替代旧实例。

3.2 电池服务层

服务层负责数据的获取和处理逻辑。在本项目中,电池数据通过平台通道从 OpenHarmony 原生层获取。服务层还负责数据的转换、缓存和错误处理。

dart 复制代码
// lib/service/battery_service.dart

import '../model/battery_model.dart';

// 电池服务类
class BatteryService {
  static final BatteryService _instance = BatteryService._internal();

  factory BatteryService() => _instance;

  BatteryService._internal();

  // 获取电池信息
  Future<BatteryInfo> getBatteryInfo() async {
    // 实际项目中通过平台通道调用原生 API
    // 这里使用模拟数据演示
    return Future.delayed(
      const Duration(milliseconds: 300),
      () => BatteryInfo(
        level: 75,
        chargingStatus: 'none',
        health: 'good',
        temperature: 28.0,
        voltage: 3800,
        currentNow: -500,
        remainingEnergy: 3800,
        totalEnergy: 5000,
      ),
    );
  }

  // 获取电池电量
  Future<int> getBatteryLevel() async {
    final info = await getBatteryInfo();
    return info.level;
  }

  // 获取充电状态
  Future<String> getChargingStatus() async {
    final info = await getBatteryInfo();
    return info.chargingStatus;
  }

  // 获取电池健康状态
  Future<String> getBatteryHealth() async {
    final info = await getBatteryInfo();
    return info.health;
  }

  // 获取电池温度
  Future<double> getBatteryTemperature() async {
    final info = await getBatteryInfo();
    return info.temperature;
  }

  // 获取电池电压
  Future<int> getBatteryVoltage() async {
    final info = await getBatteryInfo();
    return info.voltage;
  }

  // 判断是否在充电
  Future<bool> isCharging() async {
    final status = await getChargingStatus();
    return status == 'charging' || status == 'full';
  }

  // 获取功耗排行数据
  Future<List<PowerConsumptionInfo>> getPowerConsumptionData() async {
    return Future.delayed(
      const Duration(milliseconds: 200),
      () => [
        PowerConsumptionInfo(
          appName: '微信',
          packageName: 'com.tencent.mm',
          consumptionLevel: 28,
          powerConsumptionMah: 420.0,
        ),
        PowerConsumptionInfo(
          appName: '抖音',
          packageName: 'com.ss.android.ugc.aweme',
          consumptionLevel: 22,
          powerConsumptionMah: 330.0,
        ),
        PowerConsumptionInfo(
          appName: '淘宝',
          packageName: 'com.taobao.taobao',
          consumptionLevel: 15,
          powerConsumptionMah: 225.0,
        ),
        PowerConsumptionInfo(
          appName: '支付宝',
          packageName: 'com.eg.android.AlipayGphone',
          consumptionLevel: 10,
          powerConsumptionMah: 150.0,
        ),
        PowerConsumptionInfo(
          appName: 'QQ',
          packageName: 'com.tencent.mobileqq',
          consumptionLevel: 8,
          powerConsumptionMah: 120.0,
        ),
      ],
    );
  }

  // 获取后台进程列表
  Future<List<ProcessItem>> getBackgroundProcesses() async {
    return Future.delayed(
      const Duration(milliseconds: 200),
      () => [
        ProcessItem(
          appName: '微信',
          packageName: 'com.tencent.mm',
          memoryUsage: 320.0,
          cpuUsage: 2.5,
          isHighConsumption: false,
        ),
        ProcessItem(
          appName: '抖音',
          packageName: 'com.ss.android.ugc.aweme',
          memoryUsage: 450.0,
          cpuUsage: 5.8,
          isHighConsumption: true,
        ),
        ProcessItem(
          appName: '支付宝',
          packageName: 'com.eg.android.AlipayGphone',
          memoryUsage: 150.0,
          cpuUsage: 0.8,
          isHighConsumption: false,
        ),
      ],
    );
  }

  // 获取历史数据
  Future<List<HistoryData>> getHistoryData() async {
    final now = DateTime.now();
    final data = <HistoryData>[];
    double level = 85.0;

    for (int i = 23; i >= 0; i--) {
      final timestamp = now.subtract(Duration(hours: i));
      level = (level - (5 + (i % 3) * 2)).clamp(15.0, 100.0);
      final isCharging = i == 12 || i == 6;
      if (isCharging) {
        level = (level + 15).clamp(15.0, 100.0);
      }
      data.add(HistoryData(
        timestamp: timestamp,
        level: level.round(),
        isCharging: isCharging,
      ));
    }

    return data;
  }
}

服务层采用了单例模式,确保全局只有一个服务实例,避免资源浪费。同时,所有方法都设计为异步返回 Future,这符合 Flutter 响应式编程的最佳实践,便于处理耗时操作和错误情况。

3.3 工具函数层

工具函数层包含数据格式化、颜色计算等辅助功能。这些函数应该是纯函数,无副作用,便于测试和复用。

dart 复制代码
// lib/utils/battery_utils.dart

import 'package:flutter/material.dart';

// 格式化时间显示
String formatTime(int minutes) {
  if (minutes <= 0) return '计算中...';
  final hours = minutes ~/ 60;
  final mins = minutes % 60;
  if (hours > 0) {
    return '${hours}小时${mins}分钟';
  }
  return '${mins}分钟';
}

// 格式化温度显示
String formatTemperature(double temp) {
  return '${temp.toStringAsFixed(1)}°C';
}

// 格式化电压显示
String formatVoltage(int voltage) {
  return '${(voltage / 1000).toStringAsFixed(2)}V';
}

// 获取健康状态文本
String getHealthStatusText(String health) {
  const healthMap = {
    'good': '优秀',
    'overheat': '过热',
    'dead': '损坏',
    'over_voltage': '过压',
    'cold': '过冷',
    'unknown': '未知',
  };
  return healthMap[health] ?? '未知';
}

// 根据电量获取颜色
Color getBatteryLevelColor(int level) {
  if (level > 60) {
    return const Color(0xFF4CAF50); // 绿色
  } else if (level > 30) {
    return const Color(0xFFFF9800); // 橙色
  } else if (level > 15) {
    return const Color(0xFFFF5722); // 深橙
  } else {
    return const Color(0xFFF44336); // 红色
  }
}

// 根据温度获取状态信息
Map<String, dynamic> getTemperatureStatus(double temp) {
  if (temp >= 20 && temp <= 35) {
    return {'text': '正常', 'color': const Color(0xFF4CAF50)};
  } else if (temp > 35 && temp <= 40) {
    return {'text': '轻微发热', 'color': const Color(0xFFFF9800)};
  } else if (temp > 40) {
    return {'text': '过热', 'color': const Color(0xFFF44336)};
  } else if (temp < 10) {
    return {'text': '过冷', 'color': const Color(0xFF2196F3)};
  } else {
    return {'text': '偏低', 'color': const Color(0xFF03A9F4)};
  }
}

// 获取应用图标
String getAppIcon(String packageName) {
  const iconMap = {
    'com.tencent.mm': '💬',
    'com.tencent.mobileqq': '💬',
    'com.ss.android.ugc.aweme': '🎵',
    'com.eg.android.AlipayGphone': '💰',
    'com.taobao.taobao': '🛒',
    'com.autonavi.minimap': '🗺️',
    'com.tencent.tmgp.sgame': '🎮',
    'android': '⚙️',
  };
  return iconMap[packageName] ?? '📱';
}

// 获取功耗等级颜色
Color getConsumptionColor(int percentage) {
  if (percentage >= 20) {
    return const Color(0xFFF44336);
  } else if (percentage >= 10) {
    return const Color(0xFFFF9800);
  } else {
    return const Color(0xFF4CAF50);
  }
}

工具函数采用静态方法实现,便于直接调用而无需实例化。每个函数职责单一,易于理解和测试。

3.4 组件层设计

组件是 Flutter 应用的核心构成单元。本项目设计了多个可复用组件,实现关注点分离。

dart 复制代码
// lib/components/battery_circle_progress.dart

import 'package:flutter/material.dart';
import '../utils/battery_utils.dart';

// 电池电量圆环组件
class BatteryCircleProgress extends StatelessWidget {
  final int level;
  final bool isCharging;

  const BatteryCircleProgress({
    super.key,
    required this.level,
    required this.isCharging,
  });

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        SizedBox(
          width: 200,
          height: 200,
          child: Stack(
            alignment: Alignment.center,
            children: [
              // 背景圆环
              SizedBox(
                width: 180,
                height: 180,
                child: CircularProgressIndicator(
                  value: 1.0,
                  strokeWidth: 12,
                  backgroundColor: Colors.transparent,
                  valueColor: AlwaysStoppedAnimation<Color>(
                    Colors.grey.shade200,
                  ),
                ),
              ),
              // 进度圆环
              SizedBox(
                width: 180,
                height: 180,
                child: CircularProgressIndicator(
                  value: level / 100,
                  strokeWidth: 12,
                  backgroundColor: Colors.transparent,
                  valueColor: AlwaysStoppedAnimation<Color>(
                    getBatteryLevelColor(level),
                  ),
                  strokeCap: StrokeCap.round,
                ),
              ),
              // 中心文字
              Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Text(
                    '$level%',
                    style: TextStyle(
                      fontSize: 48,
                      fontWeight: FontWeight.bold,
                      color: getBatteryLevelColor(level),
                    ),
                  ),
                  if (isCharging)
                    Row(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        const Text('⚡', style: TextStyle(fontSize: 16)),
                        const SizedBox(width: 4),
                        Text(
                          '充电中',
                          style: TextStyle(
                            fontSize: 14,
                            color: Colors.grey.shade600,
                          ),
                        ),
                      ],
                    )
                  else
                    Text(
                      getRemainingText(),
                      style: TextStyle(
                        fontSize: 14,
                        color: Colors.grey.shade600,
                      ),
                    ),
                ],
              ),
            ],
          ),
        ),
      ],
    );
  }

  String getRemainingText() {
    if (level > 80) return '电量充足';
    if (level > 60) return '电量良好';
    if (level > 30) return '电量偏低';
    if (level > 15) return '电量不足';
    return '请及时充电';
  }
}

组件设计遵循单一职责原则,每个组件只负责一个功能点。圆环组件通过 CustomPaintCircularProgressIndicator 实现视觉效果,内部状态由父组件通过参数传入,实现了良好的解耦。

3.5 页面层实现

页面是应用视图的顶层容器,负责组装各个组件并管理页面级状态。

dart 复制代码
// lib/pages/battery_page.dart

import 'package:flutter/material.dart';
import '../model/battery_model.dart';
import '../service/battery_service.dart';
import '../utils/battery_utils.dart';
import '../components/battery_circle_progress.dart';
import '../components/battery_indicators.dart';
import '../components/battery_history.dart';
import '../components/process_manager.dart';
import '../components/common_components.dart';

// 电池页面主组件
class BatteryPage extends StatefulWidget {
  const BatteryPage({super.key});

  @override
  State<BatteryPage> createState() => _BatteryPageState();
}

class _BatteryPageState extends State<BatteryPage> {
  final BatteryService _batteryService = BatteryService();

  int _currentTab = 0;
  bool _isLoading = true;
  bool _powerSavingEnabled = false;
  bool _backgroundRestricted = false;

  BatteryInfo? _batteryInfo;
  List<PowerConsumptionInfo> _consumptionList = [];
  List<HistoryData> _historyData = [];
  List<ProcessItem> _processes = [];
  bool _showOptimizeDialog = false;
  String _selectedAppName = '';
  String _selectedPackageName = '';

  double _averageUsage = 35.0;
  double _screenOnTime = 4.5;
  double _drainRate = 8.2;
  String _lastFullCharge = '今天 09:30';

  @override
  void initState() {
    super.initState();
    _loadData();
  }

  Future<void> _loadData() async {
    setState(() => _isLoading = true);

    try {
      final results = await Future.wait([
        _batteryService.getBatteryInfo(),
        _batteryService.getPowerConsumptionData(),
        _batteryService.getHistoryData(),
        _batteryService.getBackgroundProcesses(),
      ]);

      setState(() {
        _batteryInfo = results[0] as BatteryInfo;
        _consumptionList = results[1] as List<PowerConsumptionInfo>;
        _historyData = results[2] as List<HistoryData>;
        _processes = results[3] as List<ProcessItem>;
        _isLoading = false;
      });
    } catch (e) {
      setState(() => _isLoading = false);
      debugPrint('Error loading battery data: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFFF5F7FA),
      body: Column(
        children: [
          _buildHeader(),
          _buildTabBar(),
          Expanded(child: _buildContent()),
        ],
      ),
    );
  }

  Widget _buildHeader() {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
      color: Colors.white,
      child: Row(
        children: [
          const Text(
            '电池优化',
            style: TextStyle(
              fontSize: 22,
              fontWeight: FontWeight.bold,
              color: Color(0xFF333333),
            ),
          ),
          const Spacer(),
          Text(
            _getStatusText(),
            style: TextStyle(
              fontSize: 13,
              color: _isCharging() ? const Color(0xFF4CAF50) : const Color(0xFF666666),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildTabBar() {
    final tabs = ['概览', '耗电排行', '使用历史', '设置'];
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      color: Colors.white,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: List.generate(tabs.length, (index) {
          return GestureDetector(
            onTap: () => setState(() => _currentTab = index),
            child: Container(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
              decoration: BoxDecoration(
                color: _currentTab == index
                    ? const Color(0xFF2196F3).withOpacity(0.1)
                    : Colors.transparent,
                borderRadius: BorderRadius.circular(8),
              ),
              child: Text(
                tabs[index],
                style: TextStyle(
                  fontSize: 15,
                  color: _currentTab == index
                      ? const Color(0xFF2196F3)
                      : const Color(0xFF999999),
                  fontWeight: _currentTab == index
                      ? FontWeight.bold
                      : FontWeight.normal,
                ),
              ),
            ),
          );
        }),
      ),
    );
  }

  Widget _buildContent() {
    if (_isLoading) {
      return const Center(child: CircularProgressIndicator());
    }

    switch (_currentTab) {
      case 0:
        return _buildOverviewTab();
      case 1:
        return _buildPowerTab();
      case 2:
        return _buildHistoryTab();
      case 3:
        return _buildSettingsTab();
      default:
        return _buildOverviewTab();
    }
  }

  Widget _buildOverviewTab() {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(20),
      child: Column(
        children: [
          BatteryCircleProgress(
            level: _batteryInfo?.level ?? 0,
            isCharging: _isCharging(),
          ),
          const SizedBox(height: 20),
          HealthStatusCard(
            health: _batteryInfo?.health ?? 'unknown',
            temperature: _batteryInfo?.temperature ?? 0,
            voltage: _batteryInfo?.voltage ?? 0,
          ),
        ],
      ),
    );
  }

  Widget _buildPowerTab() {
    return Stack(
      children: [
        SingleChildScrollView(
          padding: const EdgeInsets.all(20),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const SectionHeader(title: '耗电应用排行', icon: '📊'),
              ..._consumptionList.asMap().entries.map((entry) {
                return _buildPowerItem(entry.value, entry.key);
              }),
            ],
          ),
        ),
        if (_showOptimizeDialog)
          _buildOptimizeDialog(),
      ],
    );
  }

  Widget _buildHistoryTab() {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(20),
      child: Column(
        children: [
          BatteryHistoryChart(dataArray: _historyData),
          const SizedBox(height: 20),
          UsageStatsCard(
            averageUsage: _averageUsage,
            screenOnTime: _screenOnTime,
            drainRate: _drainRate,
            lastFullCharge: _lastFullCharge,
          ),
        ],
      ),
    );
  }

  Widget _buildSettingsTab() {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(20),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const SectionHeader(title: '省电模式', icon: '⚡'),
          ToggleCard(
            title: '省电模式',
            subtitle: '降低性能以延长电池续航',
            icon: '🔋',
            isOn: _powerSavingEnabled,
            onToggle: (value) => setState(() => _powerSavingEnabled = value),
          ),
        ],
      ),
    );
  }

  bool _isCharging() {
    final status = _batteryInfo?.chargingStatus;
    return status == 'charging' || status == 'full';
  }

  String _getStatusText() {
    if (_isCharging()) {
      return _batteryInfo?.chargingStatus == 'full' ? '已充满' : '充电中';
    }
    return '未充电';
  }
}

页面组件采用了 StatefulWidget,以便管理动态变化的状态。代码中使用了 Future.wait 并行加载多个数据源,提升了数据加载效率。

四、代码仓库

本项目的完整代码已托管至 AtomGit 平台,欢迎各位开发者 Star、Fork 并提出宝贵意见。

仓库地址https://atomgit.com/maaath/battery-optimization-flutter

五、截图运行板块

以下是应用在鸿蒙设备上的实际运行截图,验证了 Flutter for OpenHarmony 跨平台开发的可行性。

5.1 应用主界面(概览页)

应用启动后显示电池概览页面,展示了电池电量圆环、温度指示器和充电时间预估。界面流畅度良好,与原生应用无明显差异。

5.2 耗电排行页面

耗电应用排行页面以列表形式展示各应用的功耗情况,按功耗从高到低排序,直观清晰。

5.3 使用历史页面

电池历史曲线图以折线形式展示过去24小时的电量变化,用户可以清楚地了解电池使用规律。

5.4 设置页面

省电模式和后台管理等设置功能正常可用,开关切换响应迅速。

以上截图均来自实际鸿蒙设备运行效果,证明 Flutter for OpenHarmony 已具备实际应用开发的能力。

六、总结与展望

本文通过一个完整的电池优化应用案例,展示了 Flutter for OpenHarmony 跨平台开发的核心流程和关键技术点。总结起来,有以下几点经验分享:

架构设计层面,采用分层架构将 UI、业务和数据分离,是保证代码可维护性的关键。无论是 Flutter 还是原生开发,良好的架构设计都能大大降低后期维护成本。

跨平台适配层面,Flutter 的平台通道机制为调用系统原生能力提供了标准方案。开发者应该充分利用这一特性,在保证跨平台能力的同时,发挥各平台的独特优势。

性能优化层面 ,Flutter 渲染引擎的高效性保证了应用的流畅度。但在实际开发中,仍需注意避免不必要的重绘,合理使用 const 构造函数和 RepaintBoundary

生态系统层面,Flutter for OpenHarmony 仍在快速发展中,部分第三方库可能尚未完全适配。建议开发者在选择依赖时,优先选择官方推荐的方案,或考虑自己实现相关功能。

展望未来,随着 OpenHarmony 生态的不断完善和 Flutter for OpenHarmony 的持续优化,跨平台开发将在鸿蒙生态中发挥越来越重要的作用。希望本文能为广大开发者提供一些参考,共同推动国产操作系统的繁荣发展。


参考资料

相关推荐
勤劳打代码2 小时前
Flutter 架构日记 —— 可演进的 Flutter Dialog 组件
flutter·架构
aqi003 小时前
一文读懂 HarmonyOS 6.1 带来的十大重要升级
android·华为·harmonyos·鸿蒙·harmony
智能化咨询3 小时前
(105页PPT)华为智慧供应链ISC+IT蓝图规划设计方案ISC+战略愿景与蓝图设计ISC+能力框架与架构设计实施路径(附下载方式)
华为
李李李勃谦4 小时前
鸿蒙PC配色方案工具:取色、配色生成与 CSS 导出
前端·css·华为·harmonyos
SmartBrain5 小时前
《资治通鉴》20 条智慧赋能企业经营管理
华为·架构·创业创新
条tiao条5 小时前
从静态到动态:鸿蒙 ArkTS 列表组件与状态装饰器实战
华为·harmonyos
Eric_HYD6 小时前
Flutter 字体字生效原理解析
flutter
maaath6 小时前
【无标题】Flutter for OpenHarmony 的文具手账应用开发实践
flutter·华为·harmonyos
里欧跑得慢6 小时前
Flutter 主题管理:构建一致的用户界面
前端·css·flutter·web