Flutter 框架跨平台鸿蒙开发 - 风的方向
运行效果图风的方向是一款充满诗意的自然主题应用,通过追踪风的方向和速度,让用户感受自然的流动与韵律。应用以蓝色为主色调,象征着天空与海洋,配合动态粒子效果和风向罗盘,为用户带来沉浸式的自然体验。听风的声音,感受自然的呼吸。风,是自然的信使,是季节的语言。它从北方的冰雪中带来寒冷,从南方的海洋里带来温暖,从东方的森林中带来湿润,从西方的沙漠里带来干燥。每一阵风都有它的故事,每一缕风都有它的方向。本应
风的方向应用
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
一、项目概述
运行效果图


1.1 应用简介
风的方向是一款充满诗意的自然主题应用,通过追踪风的方向和速度,让用户感受自然的流动与韵律。应用以蓝色为主色调,象征着天空与海洋,配合动态粒子效果和风向罗盘,为用户带来沉浸式的自然体验。
应用核心理念:听风的声音,感受自然的呼吸。
风,是自然的信使,是季节的语言。它从北方的冰雪中带来寒冷,从南方的海洋里带来温暖,从东方的森林中带来湿润,从西方的沙漠里带来干燥。每一阵风都有它的故事,每一缕风都有它的方向。本应用通过科技的方式,让我们重新认识这位自然的朋友。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 风向罗盘 | 可视化风向显示 | CustomPainter绘制 |
| 风速显示 | 八级风速等级 | 枚举分类 |
| 粒子效果 | 风流动画效果 | 粒子系统 |
| 风向历史 | 24小时风向变化 | 折线图 |
| 天气信息 | 温度湿度显示 | 模拟数据 |
| 风之诗 | 根据风速生成诗句 | 文字映射 |
1.3 风向定义
| 序号 | 风向 | Emoji | 角度 | 描述 |
|---|---|---|---|---|
| 1 | 北风 | ⬆️ | 0° | 来自北方的寒风 |
| 2 | 东北风 | ↗️ | 45° | 东北方向的微风 |
| 3 | 东风 | ➡️ | 90° | 东方吹来的湿润之风 |
| 4 | 东南风 | ↘️ | 135° | 东南方向的暖风 |
| 5 | 南风 | ⬇️ | 180° | 来自南方的温暖之风 |
| 6 | 西南风 | ↙️ | 225° | 西南方向的柔风 |
| 7 | 西风 | ⬅️ | 270° | 西方吹来的干燥之风 |
| 8 | 西北风 | ↖️ | 315° | 西北方向的冷风 |
1.4 风速等级
| 等级 | 名称 | Emoji | 风速范围 | 描述 |
|---|---|---|---|---|
| 0 | 无风 | 🍃 | 0-0.2 m/s | 树叶静止,炊烟直上 |
| 1 | 微风 | 🌿 | 0.3-1.5 m/s | 树叶微动,轻拂面颊 |
| 2 | 轻风 | 🌱 | 1.6-3.3 m/s | 树叶摇动,旗帜飘扬 |
| 3 | 和风 | 🌾 | 3.4-5.4 m/s | 小枝摇动,灰尘飞扬 |
| 4 | 清风 | 🌴 | 5.5-7.9 m/s | 小树摇摆,水波荡漾 |
| 5 | 强风 | 🌳 | 8.0-10.7 m/s | 大树摇动,举伞困难 |
| 6 | 疾风 | 🌲 | 10.8-13.8 m/s | 树枝折断,行走困难 |
| 7 | 大风 | 🏔️ | 13.9-17.1 m/s | 树木连根拔起 |
1.5 技术栈
| 技术领域 | 技术选型 | 版本要求 |
|---|---|---|
| 开发框架 | Flutter | >= 3.0.0 |
| 编程语言 | Dart | >= 2.17.0 |
| 设计规范 | Material Design 3 | - |
| 状态管理 | setState | - |
| 动画控制 | AnimationController | - |
| 自定义绘制 | CustomPainter | - |
| 定时器 | Timer | - |
| 目标平台 | 鸿蒙OS / Web | API 21+ |
二、项目结构
lib/
├── main_wind_direction.dart # 应用主入口(~750行)
│ ├── WindDirectionApp # 根应用组件
│ ├── WindDirection # 风向枚举
│ ├── WindSpeed # 风速枚举
│ ├── WindData # 风数据模型
│ ├── WindParticle # 粒子模型
│ ├── WindDirectionHomePage # 主页面
│ ├── ArrowPainter # 箭头绘制器
│ ├── ParticlePainter # 粒子绘制器
│ └── WindHistoryPainter # 历史绘制器
三、数据模型
3.1 风向枚举 (WindDirection)
enum WindDirection {
north('北风', '⬆️', 0, '来自北方的寒风'),
northEast('东北风', '↗️', 45, '东北方向的微风'),
east('东风', '➡️', 90, '东方吹来的湿润之风'),
southEast('东南风', '↘️', 135, '东南方向的暖风'),
south('南风', '⬇️', 180, '来自南方的温暖之风'),
southWest('西南风', '↙️', 225, '西南方向的柔风'),
west('西风', '⬅️', 270, '西方吹来的干燥之风'),
northWest('西北风', '↖️', 315, '西北方向的冷风');
final String label; // 风向名称
final String icon; // 代表图标
final int degree; // 角度
final String description; // 描述
// 从角度计算风向
static WindDirection fromDegree(int degree) {
final normalizedDegree = ((degree % 360) + 360) % 360;
final index = ((normalizedDegree + 22.5) ~/ 45) % 8;
return WindDirection.values[index];
}
}
3.2 风速枚举 (WindSpeed)
enum WindSpeed {
calm('无风', '🍃', 0, 0.2, '树叶静止,炊烟直上'),
light('微风', '🌿', 0.3, 1.5, '树叶微动,轻拂面颊'),
gentle('轻风', '🌱', 1.6, 3.3, '树叶摇动,旗帜飘扬'),
moderate('和风', '🌾', 3.4, 5.4, '小枝摇动,灰尘飞扬'),
fresh('清风', '🌴', 5.5, 7.9, '小树摇摆,水波荡漾'),
strong('强风', '🌳', 8.0, 10.7, '大树摇动,举伞困难'),
gale('疾风', '🌲', 10.8, 13.8, '树枝折断,行走困难'),
storm('大风', '🏔️', 13.9, 17.1, '树木连根拔起');
final String label; // 等级名称
final String icon; // 代表图标
final double minSpeed; // 最小风速
final double maxSpeed; // 最大风速
final String description; // 描述
// 从风速值计算等级
static WindSpeed fromSpeed(double speed) {
for (var ws in WindSpeed.values) {
if (speed >= ws.minSpeed && speed <= ws.maxSpeed) {
return ws;
}
}
return WindSpeed.storm;
}
}
3.3 风数据模型 (WindData)
class WindData {
final WindDirection direction; // 风向
final WindSpeed speed; // 风速等级
final double speedValue; // 风速值(m/s)
final DateTime timestamp; // 时间戳
final double temperature; // 温度
final int humidity; // 湿度
}
3.4 粒子模型 (WindParticle)
class WindParticle {
double x; // X坐标(0.0-1.0)
double y; // Y坐标(0.0-1.0)
double speed; // 移动速度
double size; // 粒子大小
double opacity; // 透明度
double angle; // 角度
}
3.5 数据流转图
四、核心功能实现
4.1 风向计算
从角度计算风向的算法:
static WindDirection fromDegree(int degree) {
// 规范化角度到0-360度
final normalizedDegree = ((degree % 360) + 360) % 360;
// 计算风向索引(每个风向占45度)
final index = ((normalizedDegree + 22.5) ~/ 45) % 8;
return WindDirection.values[index];
}
计算原理:
index=⌊degree+22.545⌋mod 8 index = \lfloor \frac{degree + 22.5}{45} \rfloor \mod 8 index=⌊45degree+22.5⌋mod8
其中:
- degreedegreedegree 为原始角度(0-360°)
- 22.522.522.5 为偏移量,确保边界正确
- 454545 为每个风向的角度范围
- 888 为风向总数
4.2 风速等级判断
static WindSpeed fromSpeed(double speed) {
for (var ws in WindSpeed.values) {
if (speed >= ws.minSpeed && speed <= ws.maxSpeed) {
return ws;
}
}
return WindSpeed.storm;
}
4.3 风数据生成
WindData _generateWindData({DateTime? timestamp}) {
final degree = _random.nextInt(360);
final speed = _random.nextDouble() * 15;
final direction = WindDirection.fromDegree(degree);
final windSpeed = WindSpeed.fromSpeed(speed);
return WindData(
direction: direction,
speed: windSpeed,
speedValue: speed,
timestamp: timestamp ?? DateTime.now(),
temperature: 15 + _random.nextDouble() * 20,
humidity: 40 + _random.nextInt(40),
);
}
4.4 粒子系统更新
void _updateParticles() {
if (_currentWind == null) return;
final windAngle = _currentWind!.direction.degree * pi / 180;
for (var particle in _particles) {
// 根据风向和风速更新粒子位置
particle.x += cos(windAngle) * particle.speed * (_currentWind!.speedValue / 5);
particle.y += sin(windAngle) * particle.speed * (_currentWind!.speedValue / 5);
// 边界检测和重生
if (particle.x < 0 || particle.x > 1 || particle.y < 0 || particle.y > 1) {
particle.x = _random.nextDouble();
particle.y = _random.nextDouble();
particle.opacity = 0.3 + _random.nextDouble() * 0.5;
}
}
setState(() {});
}
4.5 罗盘箭头绘制
class ArrowPainter extends CustomPainter {
final Color color;
void paint(Canvas canvas, Size size) {
final center = Offset(size.width / 2, size.height / 2);
final paint = Paint()
..color = color
..style = PaintingStyle.fill;
// 绘制箭头路径
final path = Path();
path.moveTo(center.dx, center.dy - 70);
path.lineTo(center.dx - 15, center.dy + 20);
path.lineTo(center.dx, center.dy + 10);
path.lineTo(center.dx + 15, center.dy + 20);
path.close();
canvas.drawPath(path, paint);
// 添加发光效果
final shadowPaint = Paint()
..color = color.withValues(alpha: 0.3)
..maskFilter = const MaskFilter.blur(BlurStyle.normal, 10);
canvas.drawPath(path, shadowPaint);
}
}
五、UI设计
5.1 色彩系统
应用以蓝色为主色调,象征天空与海洋:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 背景渐变1 | #1A237E | 深蓝 |
| 背景渐变2 | #0277BD | 中蓝 |
| 背景渐变3 | #00BCD4 | 青色 |
| 主色调 | #00BCD4 | 青色 |
| 罗盘颜色 | #B2EBF2 | 浅青 |
| 文字主色 | #FFFFFF | 白色 |
| 文字辅色 | #FFFFFF 80% | 半透明白 |
5.2 页面结构
┌─────────────────────────────────────┐
│ 🌬️ 风的方向 🌡️25° 💧65% │ ← 标题栏
│ 追踪风的方向,感受自然的流动 │
├─────────────────────────────────────┤
│ │
│ N │
│ ╱ ╲ │
│ W ───── E │ ← 风向罗盘
│ ╲ ╱ │
│ S │
│ ↗️ │
│ 东北风 │
│ 3.5 m/s │
│ │
├─────────────────────────────────────┤
│ ↗️东北风 🌾和风 3.5m/s │ ← 风速信息
│ ℹ️ 小枝摇动,灰尘飞扬 │
├─────────────────────────────────────┤
│ │
│ · · · · · · · · │ ← 粒子效果
│ · · · · · · · │
│ · · · · · · · · │
│ │
├─────────────────────────────────────┤
│ 风向变化 最近24小时 │
│ ∿∿∿∿∿∿∿∿∿∿∿∿∿∿∿∿∿∿∿ │ ← 历史曲线
│ │
├─────────────────────────────────────┤
│ 📖 风之诗 │
│ │
│ 轻风过林梢 │ ← 诗句展示
│ 枝叶舞翩跹 │
│ 鸟鸣声声脆 │
│ 心随自然闲 │
└─────────────────────────────────────┘
5.3 罗盘设计
5.3.1 罗盘结构
N (0°)
↑
│
W ←─────┼─────→ E (90°)
(270°) │ (90°)
↓
S (180°)
5.3.2 风向角度映射
5.4 交互设计
| 交互元素 | 触发方式 | 响应行为 |
|---|---|---|
| 罗盘箭头 | 自动 | 根据风向旋转 |
| 粒子动画 | 自动 | 随风向流动 |
| 风数据 | 每5秒 | 自动更新 |
| 历史曲线 | 自动 | 实时绘制 |
六、动画详解
6.1 动画控制器
应用使用三个动画控制器:
// 罗盘旋转动画
_compassController = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
);
// 粒子更新动画
_particleController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 50),
)..addListener(_updateParticles);
// 脉冲呼吸动画
_pulseController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1500),
)..repeat(reverse: true);
6.2 罗盘旋转动画
AnimatedBuilder(
animation: _compassController,
builder: (context, child) {
final targetAngle = _currentWind!.direction.degree * pi / 180;
final animationValue = Curves.easeOutCubic.transform(_compassController.value);
final currentAngle = targetAngle * animationValue;
return Transform.rotate(
angle: currentAngle,
child: CustomPaint(
painter: ArrowPainter(color: Colors.cyan.shade300),
),
);
},
)
6.3 动画时序图
七、风之诗系统
7.1 诗句映射
根据风速等级生成不同的诗句:
| 风速 | 诗句 |
|---|---|
| 无风 | 风静叶无声 云淡天高远 一缕炊烟直 岁月正安然 |
| 微风 | 微风拂面来 轻摇树叶间 似有还无迹 春意正阑珊 |
| 轻风 | 轻风过林梢 枝叶舞翩跹 鸟鸣声声脆 心随自然闲 |
| 和风 | 和风送清凉 尘土舞飞扬 旗帜猎猎响 天地正苍茫 |
| 清风 | 清风拂大地 水波荡涟漪 小树随风舞 心旷神怡时 |
| 强风 | 强风撼大树 举步显艰难 风中行路人 意志更坚强 |
| 疾风 | 疾风扫落叶 树枝折断声 天地变色时 唯有心不惊 |
| 大风 | 大风起兮云飞扬 威加海内兮归故乡 安得猛士兮守四方 |
7.2 诗句生成逻辑
String _getWindPoetry() {
if (_currentWind == null) return '';
final poetries = {
WindSpeed.calm: '风静叶无声\n云淡天高远\n一缕炊烟直\n岁月正安然',
WindSpeed.light: '微风拂面来\n轻摇树叶间\n似有还无迹\n春意正阑珊',
// ... 更多诗句
};
return poetries[_currentWind!.speed] ?? '';
}
八、状态管理
8.1 状态分类
| 状态类型 | 状态名称 | 说明 |
|---|---|---|
| 当前风数据 | _currentWind |
当前风向风速 |
| 历史记录 | _windHistory |
24小时历史 |
| 粒子列表 | _particles |
粒子系统数据 |
| 风数据定时器 | _windTimer |
定时更新风数据 |
8.2 数据更新流程
九、性能优化
9.1 渲染优化
| 优化点 | 实现方式 | 效果 |
|---|---|---|
| 粒子数量 | 限制50个粒子 | 控制渲染量 |
| 重绘策略 | shouldRepaint返回true | 实时更新 |
| 定时器管理 | 及时取消Timer | 避免内存泄漏 |
| 动画释放 | dispose中释放 | 释放资源 |
9.2 内存管理
void dispose() {
_windTimer?.cancel();
_compassController.dispose();
_particleController.dispose();
_pulseController.dispose();
super.dispose();
}
9.3 性能指标
| 指标 | 目标值 | 实测值 |
|---|---|---|
| 动画帧率 | 60fps | 60fps |
| 内存占用 | < 50MB | 待测试 |
| 启动时间 | < 2s | 待测试 |
| CPU占用 | < 15% | 待测试 |
十、常见问题
10.1 问题排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 罗盘不旋转 | 动画未启动 | 检查_animateCompass |
| 粒子不移动 | 更新未触发 | 检查_updateParticles |
| 风向错误 | 角度计算错误 | 检查fromDegree方法 |
| 内存泄漏 | Timer未取消 | 在dispose中取消 |
10.2 调试技巧
// 打印风数据
debugPrint('Direction: ${_currentWind?.direction.label}');
debugPrint('Speed: ${_currentWind?.speedValue} m/s');
debugPrint('Speed Level: ${_currentWind?.speed.label}');
// 打印粒子数量
debugPrint('Particles: ${_particles.length}');
// 打印历史记录
debugPrint('History: ${_windHistory.length} records');
十一、运行说明
11.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 21+ |
11.2 运行命令
# 查看可用设备
flutter devices
# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_wind_direction.dart
# 运行到Web服务器
flutter run -d web-server -t lib/main_wind_direction.dart --web-port 8124
# 运行到Windows
flutter run -d windows -t lib/main_wind_direction.dart
# 代码分析
flutter analyze lib/main_wind_direction.dart
十二、扩展建议
12.1 功能扩展
| 功能 | 优先级 | 实现思路 |
|---|---|---|
| 真实天气API | 高 | 接入天气服务API |
| 地理定位 | 高 | 获取用户位置 |
| 风向预报 | 中 | 未来风向预测 |
| 历史记录 | 中 | 本地数据存储 |
| 分享功能 | 低 | 分享风向信息 |
| 语音播报 | 低 | 语音播报风向 |
12.2 设计扩展
| 方向 | 描述 |
|---|---|
| 更多主题 | 日出、日落、星空等主题 |
| 音效反馈 | 风声音效 |
| 振动反馈 | 风速振动 |
| AR效果 | 增强现实风向显示 |
12.3 技术扩展
十三、自然科学价值
13.1 应用价值
风的方向应用具有重要的自然科学价值:
- 气象认知:帮助用户了解风向风速的基本概念
- 自然感知:增强用户对自然环境的感知能力
- 诗意生活:将科学与艺术结合,提升生活品质
- 环保意识:培养关注自然、保护环境的意识
13.2 教育意义
13.3 使用场景
| 场景 | 适用人群 | 预期效果 |
|---|---|---|
| 户外活动 | 登山者、帆船爱好者 | 了解风况,规划活动 |
| 气象学习 | 学生群体 | 学习气象知识 |
| 休闲放松 | 都市人群 | 感受自然,放松心情 |
| 艺术创作 | 文艺爱好者 | 获取灵感,创作作品 |
十四、总结
风的方向应用通过风向罗盘、粒子动画、风之诗等创新元素,为用户提供了一种独特的自然体验方式。应用核心亮点包括:
14.1 核心特色
- 风向罗盘:可视化风向显示,直观易懂
- 八级风速:科学分级,详细描述
- 粒子动画:动态展示风的流动
- 风向历史:24小时变化趋势
- 风之诗:科学与艺术的完美结合
14.2 技术亮点
- 枚举类型设计:风向、风速使用枚举,代码清晰
- 角度计算算法:精确的风向角度映射
- 粒子系统:流畅的风流动画效果
- CustomPainter:高效的自定义绘制
- 动画控制器:多个动画协同工作
14.3 应用价值
风的方向不仅是一个气象工具,更是一次关于自然与艺术的探索。它让我们重新认识风这位自然的朋友,在科技的帮助下感受自然的韵律与诗意。
听风的声音,感受自然的呼吸!
愿每一阵风都能带来心灵的宁静 🌬️
更多推荐




所有评论(0)