重力感知应用
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
一、项目概述
运行效果图



1.1 应用简介
重力感知是一款基于传感器技术的数据记录应用,通过模拟重力传感器记录一天的重力变化轨迹。应用将抽象的重力数据转化为直观的可视化图表,让用户能够看到地球引力在一天中的微妙变化。
应用以深蓝色为主色调,象征宇宙与科技。界面设计现代感十足,采用深色主题营造科技氛围。通过轨道动画展示重力场的概念,将三轴加速度数据实时展示,帮助用户理解重力的本质。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 重力感知 | 实时显示重力数据 | 模拟传感器 |
| 轨道动画 | 重力场可视化 | CustomPaint绘制 |
| 三轴显示 | X/Y/Z轴加速度 | 数值展示 |
| 数据记录 | 记录重力轨迹 | Timer定时采集 |
| 历史查看 | 查看历史记录 | 列表展示 |
| 数据分析 | 统计分析重力数据 | 算法计算 |
1.3 重力数据说明
| 数据项 | 说明 | 单位 |
|---|---|---|
| X轴加速度 | 水平方向加速度 | m/s² |
| Y轴加速度 | 垂直方向加速度 | m/s² |
| Z轴加速度 | 深度方向加速度 | m/s² |
| 重力大小 | 合成加速度大小 | m/s² |
| 标准重力 | 地球标准重力加速度 | 9.80665 m/s² |
1.4 技术栈
| 技术领域 | 技术选型 | 版本要求 |
|---|---|---|
| 开发框架 | Flutter | >= 3.0.0 |
| 编程语言 | Dart | >= 2.17.0 |
| 设计规范 | Material Design 3 | - |
| 状态管理 | setState | - |
| 动画系统 | AnimationController | - |
| 图形绘制 | CustomPaint | - |
| 目标平台 | 鸿蒙OS / Web | API 21+ |
1.5 项目结构
lib/
└── main_gravity_sensor.dart
├── GravitySensorApp # 应用入口
├── GravityData # 重力数据模型
├── GravitySession # 重力会话模型
├── GravitySensorHomePage # 主页面(底部导航)
├── _buildSensorPage # 感知页面
├── _buildHistoryPage # 历史页面
├── _buildAnalysisPage # 分析页面
├── OrbitPainter # 轨道绘制器
├── MiniGravityPainter # 迷你图表绘制器
└── DetailGravityPainter # 详情图表绘制器
二、设计理念
2.1 重力感知概念
重力感知
数据采集
可视化
轨迹记录
X轴加速度
Y轴加速度
Z轴加速度
合成重力
轨道动画
三轴显示
重力曲线
实时记录
历史存储
数据分析
2.2 重力场可视化
重力场
轨道动画
三层轨道
运动粒子
循环动画
重力球体
中心显示
数值展示
渐变效果
三轴数据
X轴 红色
Y轴 绿色
Z轴 蓝色
2.3 色彩体系
应用采用深蓝色为主色调:
| 颜色类型 | 色值 | RGB | 用途 |
|---|---|---|---|
| 主色 | #3F51B5 | 63,81,181 | 导航、按钮、强调 |
| 辅助色 | #5C6BC0 | 92,107,192 | 渐变、次要元素 |
| 背景1 | #0F0F1E | 15,15,30 | 主背景 |
| 背景2 | #1A1A2E | 26,26,46 | 卡片背景 |
| 背景3 | #16213E | 22,33,62 | 次背景 |
| X轴 | Red | - | X轴加速度 |
| Y轴 | Green | - | Y轴加速度 |
| Z轴 | Blue | - | Z轴加速度 |
2.4 重力数据流程
存储 可视化 数据处理 传感器 存储 可视化 数据处理 传感器 alt [正在记录] 采集三轴数据 计算合成重力 更新显示 保存数据点 更新历史列表
三、系统架构
3.1 整体架构图
Data Layer
Business Layer
Presentation Layer
主页面
GravitySensorHomePage
感知页
历史页
分析页
轨道动画
三轴显示
重力球体
记录列表
详情弹窗
统计卡片
分布图表
传感器模拟
数据生成
记录系统
Timer采集
分析引擎
统计算法
GravityData
数据模型
GravitySession
会话模型
3.2 类图设计
manages
records
extends
GravitySensorApp
+Widget build()
GravityData
+DateTime timestamp
+double x
+double y
+double z
+double magnitude
GravitySession
+String id
+DateTime startTime
+DateTime endTime
+List<GravityData> dataPoints
+double avgMagnitude
+double maxMagnitude
+double minMagnitude
GravitySensorHomePage
-int _currentIndex
-List<GravitySession> _sessions
-List<GravityData> _currentDataPoints
-bool _isRecording
-Timer _recordingTimer
-double _currentX
-double _currentY
-double _currentZ
-double _currentMagnitude
-AnimationController _orbitController
+void _startRecording()
+void _stopRecording()
+void _startSimulation()
OrbitPainter
+double progress
+double magnitude
+void paint()
+bool shouldRepaint()
CustomPainter
3.3 数据记录流程
存储 记录系统 传感器模拟 感知页 用户 存储 记录系统 传感器模拟 感知页 用户 loop [每100ms] 打开应用 启动模拟 实时数据更新 开始记录 启动Timer 采集数据点 保存数据 停止记录 停止Timer 创建会话 显示摘要
四、核心功能实现
4.1 传感器模拟
模拟重力传感器数据:
dart
void _startSimulation() {
Timer.periodic(const Duration(milliseconds: 100), (timer) {
if (!mounted) {
timer.cancel();
return;
}
final random = Random();
setState(() {
// 模拟三轴加速度
_currentX = (random.nextDouble() - 0.5) * 2;
_currentY = (random.nextDouble() - 0.5) * 2;
_currentZ = 9.8 + (random.nextDouble() - 0.5) * 0.5;
// 计算合成重力
_currentMagnitude = sqrt(
_currentX * _currentX +
_currentY * _currentY +
_currentZ * _currentZ,
);
});
});
}
4.2 轨道动画绘制
绘制重力场轨道动画:
dart
class OrbitPainter extends CustomPainter {
final double progress;
final double magnitude;
@override
void paint(Canvas canvas, Size size) {
final center = Offset(size.width / 2, size.height / 2);
final baseRadius = size.width / 2 - 20;
// 绘制三层轨道
for (int i = 0; i < 3; i++) {
final orbitProgress = (progress + i * 0.33) % 1.0;
final radius = baseRadius - i * 30;
final angle = orbitProgress * 2 * pi;
// 绘制轨道圆
final paint = Paint()
..color = const Color(0xFF3F51B5).withValues(alpha: 0.3 - i * 0.1)
..style = PaintingStyle.stroke
..strokeWidth = 1;
canvas.drawCircle(center, radius, paint);
// 绘制轨道上的粒子
final dotX = center.dx + radius * cos(angle);
final dotY = center.dy + radius * sin(angle);
final dotPaint = Paint()
..color = const Color(0xFF3F51B5).withValues(alpha: 0.8)
..style = PaintingStyle.fill;
canvas.drawCircle(Offset(dotX, dotY), 4, dotPaint);
}
}
}
4.3 数据记录系统
记录重力轨迹:
dart
void _startRecording() {
setState(() {
_isRecording = true;
_currentDataPoints = [];
_recordingStartTime = DateTime.now();
});
_recordingTimer = Timer.periodic(const Duration(milliseconds: 100), (timer) {
setState(() {
_currentDataPoints.add(GravityData(
timestamp: DateTime.now(),
x: _currentX,
y: _currentY,
z: _currentZ,
magnitude: _currentMagnitude,
));
});
});
}
void _stopRecording() {
_recordingTimer?.cancel();
if (_currentDataPoints.isEmpty) {
setState(() {
_isRecording = false;
});
return;
}
// 计算统计数据
final magnitudes = _currentDataPoints.map((d) => d.magnitude).toList();
final session = GravitySession(
id: DateTime.now().millisecondsSinceEpoch.toString(),
startTime: _recordingStartTime!,
endTime: DateTime.now(),
dataPoints: List.from(_currentDataPoints),
avgMagnitude: magnitudes.reduce((a, b) => a + b) / magnitudes.length,
maxMagnitude: magnitudes.reduce(max),
minMagnitude: magnitudes.reduce(min),
);
setState(() {
_sessions.insert(0, session);
_isRecording = false;
_currentDataPoints = [];
});
}
4.4 重力曲线绘制
绘制重力变化曲线:
dart
class DetailGravityPainter extends CustomPainter {
final List<GravityData> dataPoints;
@override
void paint(Canvas canvas, Size size) {
if (dataPoints.isEmpty) return;
final paint = Paint()
..color = const Color(0xFF3F51B5)
..style = PaintingStyle.stroke
..strokeWidth = 2;
final path = Path();
final points = <Offset>[];
// 计算数据点位置
for (int i = 0; i < dataPoints.length; i++) {
final x = (i / (dataPoints.length - 1)) * size.width;
final y = size.height - ((dataPoints[i].magnitude - 9.5) / 1.0 * size.height);
points.add(Offset(x, y.clamp(0, size.height)));
}
// 绘制平滑曲线
for (int i = 0; i < points.length; i++) {
if (i == 0) {
path.moveTo(points[i].dx, points[i].dy);
} else {
final prevPoint = points[i - 1];
final controlPoint = Offset(
(prevPoint.dx + points[i].dx) / 2,
(prevPoint.dy + points[i].dy) / 2,
);
path.quadraticBezierTo(
prevPoint.dx, prevPoint.dy,
controlPoint.dx, controlPoint.dy,
);
}
}
canvas.drawPath(path, paint);
// 绘制填充渐变
final fillPaint = Paint()
..shader = LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
const Color(0xFF3F51B5).withValues(alpha: 0.3),
const Color(0xFF3F51B5).withValues(alpha: 0.0),
],
).createShader(Rect.fromLTWH(0, 0, size.width, size.height))
..style = PaintingStyle.fill;
final fillPath = Path.from(path);
fillPath.lineTo(size.width, size.height);
fillPath.lineTo(0, size.height);
fillPath.close();
canvas.drawPath(fillPath, fillPaint);
}
}
五、UI设计规范
5.1 配色方案
应用采用深蓝色为主色调:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 主色 | #3F51B5 (Indigo) | 导航、按钮、强调 |
| 辅助色 | #5C6BC0 | 渐变、次要元素 |
| 背景1 | #0F0F1E | 主背景 |
| 背景2 | #1A1A2E | 卡片背景 |
| 背景3 | #16213E | 次背景 |
5.2 字体规范
| 元素 | 字号 | 字重 | 颜色 |
|---|---|---|---|
| 页面标题 | 24-28px | Bold | #FFFFFF |
| 重力数值 | 24px | Bold | #FFFFFF |
| 轴标签 | 14px | Bold | 动态颜色 |
| 数值显示 | 16-18px | Bold | #3F51B5 |
| 辅助文字 | 11-14px | Regular | 50-70% White |
5.3 组件规范
5.3.1 重力球体
╭─────────────╮
╱ ╭───────╮ ╲
│ ╱ 9.81 ╲ │
│ │ m/s² │ │
│ ╲ ╱ │
╲ ╰───────╯ ╱
╰─────────────╯
5.3.2 三轴显示
┌──────────────────────────────────┐
│ X Y Z │
│ ╭───╮ ╭───╮ ╭───╮ │
│ │0.5│ │-0.3│ │9.8│ │
│ ╰───╯ ╰───╯ ╰───╯ │
│ 红 绿 蓝 │
└──────────────────────────────────┘
5.3.3 重力曲线
┌────────────────────────────────────┐
│ │
│ ╱╲ ╱╲ │
│ ╱ ╲ ╱ ╲ ╱╲ │
│ ╱ ╲╱ ╲ ╱ ╲ │
│ ╱ ╲╱ ╲ │
│ │
└────────────────────────────────────┘
六、交互设计
6.1 数据记录流程
存储 Timer 记录按钮 感知页 用户 存储 Timer 记录按钮 感知页 用户 loop [每100ms] 查看实时数据 显示重力球体 点击开始 启动定时器 保存数据点 更新计数 点击停止 停止定时器 创建会话 显示摘要
6.2 轨道动画机制
轨道动画
三层轨道
外层轨道
中层轨道
内层轨道
最大半径
最慢速度
中等半径
中等速度
最小半径
最快速度
粒子运动
6.3 页面切换状态
点击历史Tab
点击分析Tab
点击感知Tab
点击分析Tab
点击感知Tab
点击历史Tab
感知页
历史页
分析页
七、数据分析
7.1 重力数据统计
| 统计项 | 计算方式 | 说明 |
|---|---|---|
| 平均重力 | 所有数据点的平均值 | 整体水平 |
| 最大重力 | 所有数据点的最大值 | 峰值 |
| 最小重力 | 所有数据点的最小值 | 谷值 |
| 波动范围 | 最大值 - 最小值 | 变化幅度 |
7.2 三轴数据分析
dart
// X轴加速度:水平方向
_currentX = (random.nextDouble() - 0.5) * 2; // -1 到 1
// Y轴加速度:垂直方向
_currentY = (random.nextDouble() - 0.5) * 2; // -1 到 1
// Z轴加速度:深度方向(主要重力分量)
_currentZ = 9.8 + (random.nextDouble() - 0.5) * 0.5; // 约 9.55 到 10.05
// 合成重力
_currentMagnitude = sqrt(x*x + y*y + z*z);
7.3 重力分布分析
| 轴 | 正常范围 | 说明 |
|---|---|---|
| X轴 | -1 ~ 1 m/s² | 水平方向加速度 |
| Y轴 | -1 ~ 1 m/s² | 垂直方向加速度 |
| Z轴 | 9.5 ~ 10.0 m/s² | 主要重力分量 |
| 合成 | 9.5 ~ 10.2 m/s² | 总体重力大小 |
八、扩展功能规划
8.1 后续版本规划
2024-01-07 2024-01-14 2024-01-21 2024-01-28 2024-02-04 2024-02-11 2024-02-18 2024-02-25 2024-03-03 2024-03-10 2024-03-17 传感器模拟 轨道动画 数据记录 历史查看 真实传感器 数据导出 分享功能 地理定位 云端同步 AI分析 V1.0 基础版本 V1.1 增强版本 V1.2 进阶版本 重力感知开发计划
8.2 功能扩展建议
8.2.1 真实传感器接入
接入真实重力传感器:
- 使用sensors_plus插件
- 获取真实加速度计数据
- 支持陀螺仪数据
- 实时数据流处理
8.2.2 地理位置关联
关联地理位置信息:
- GPS定位集成
- 海拔高度影响
- 地理位置标记
- 地图可视化
8.2.3 数据导出
支持多种格式导出:
- CSV格式导出
- JSON数据导出
- 图表图片导出
- 数据分析报告
九、注意事项
9.1 开发注意事项
-
传感器模拟:当前使用模拟数据,实际应用需接入真实传感器
-
动画性能:轨道动画需要优化性能
-
数据存储:大量数据点需要注意内存管理
-
状态管理:使用setState管理本地状态
9.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 轨道不显示 | CustomPaint未正确实现 | 检查OrbitPainter |
| 数据不更新 | Timer未启动 | 检查_startSimulation |
| 记录为空 | Timer未正确保存 | 检查_recordingTimer |
| 曲线不显示 | 数据点为空 | 检查dataPoints |
9.3 使用提示
🌍 重力感知使用小贴士 🌍
地球标准重力加速度约为 9.80665 m/s²。
重力会因地理位置和海拔而略有不同。
记录重力轨迹可以了解设备运动状态。
持续记录可以发现重力的微小变化。
提示:建议在静止状态下记录,数据更准确。
十、运行说明
10.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 21+ |
10.2 运行命令
bash
# 查看可用设备
flutter devices
# 运行到Web服务器
flutter run -d web-server -t lib/main_gravity_sensor.dart --web-port 8127
# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_gravity_sensor.dart
# 运行到Windows
flutter run -d windows -t lib/main_gravity_sensor.dart
# 代码分析
flutter analyze lib/main_gravity_sensor.dart
十一、总结
重力感知是一款基于传感器技术的数据记录应用,通过模拟重力传感器记录一天的重力变化轨迹。应用将抽象的重力数据转化为直观的可视化图表,让用户能够看到地球引力在一天中的微妙变化。
从技术实现来看,应用使用模拟数据模拟重力传感器,通过CustomPaint绘制轨道动画和重力曲线,使用Timer定时采集数据点,实现了完整的重力数据记录和分析系统。
从用户体验来看,应用提供直观的重力场可视化,通过轨道动画展示重力场的概念。三轴加速度实时显示,帮助用户理解重力的本质。重力曲线绘制,让用户看到重力的变化轨迹。
应用不仅是一个数据记录工具,更是一个科学教育平台。它提醒我们:地球标准重力加速度约为 9.80665 m/s²;重力会因地理位置和海拔而略有不同;记录重力轨迹可以了解设备运动状态;持续记录可以发现重力的微小变化。在科技与自然的交汇点,重力感知为我们提供了一种探索世界的新方式。
记录地球引力的轨迹