在鸿蒙HarmonyOS 5中使用HarmonyOS Design实现检测运动的应用程序
·
设计概述
基于HarmonyOS 5的运动健康服务能力和HarmonyOS Design规范,我们将创建一个功能全面的运动检测应用,包含实时运动数据监测、运动类型识别、历史记录和健康分析等功能。
核心功能实现
1. 主界面设计 (ArkUI)
// MainPage.ets
@Entry
@Component
struct MainPage {
@State currentTab: number = 0
build() {
Column() {
// 运动数据概览
if (this.currentTab === 0) {
MotionOverview()
.margin({ top: 16 })
}
// 内容区
Tabs({ barPosition: BarPosition.End }) {
TabContent() {
MotionTrackingPage()
}.tabBar('运动监测')
TabContent() {
HistoryPage()
}.tabBar('历史记录')
TabContent() {
AnalysisPage()
}.tabBar('健康分析')
}
.barWidth('100%')
.barHeight(56)
.onChange((index: number) => {
this.currentTab = index
})
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
}
2. 运动监测页面
// MotionTrackingPage.ets
@Component
struct MotionTrackingPage {
@State isTracking: boolean = false
@State currentMotionType: string = '未开始'
@State steps: number = 0
@State distance: number = 0.0
@State calories: number = 0
@State heartRate: number = 0
@State timer: number = 0
private sensorManager: sensor.SensorManager = sensor.getSensorManager()
private stepCounter: sensor.StepCounter | null = null
aboutToAppear() {
// 初始化传感器
this.initSensors()
}
private initSensors() {
// 获取步数计数器
this.stepCounter = this.sensorManager.getDefaultSensor(sensor.SensorId.STEP_COUNTER)
// 注册传感器回调
this.sensorManager.on(sensor.SensorId.STEP_COUNTER, (data: sensor.SensorData) => {
this.steps = data.steps
this.calculateDerivedMetrics()
})
}
private calculateDerivedMetrics() {
// 计算距离和卡路里(简化计算)
this.distance = this.steps * 0.7 // 假设步长0.7米
this.calories = this.steps * 0.04 // 简化计算
}
build() {
Column() {
// 运动类型选择
MotionTypeSelector({
onTypeSelected: (type: string) => {
this.currentMotionType = type
}
})
.margin({ bottom: 20 })
// 实时数据展示
Grid() {
GridItem() {
MetricCard({
value: this.timer.toString(),
unit: '时间',
icon: $r('app.media.ic_timer')
})
}
GridItem() {
MetricCard({
value: this.steps.toString(),
unit: '步数',
icon: $r('app.media.ic_steps')
})
}
GridItem() {
MetricCard({
value: this.distance.toFixed(2),
unit: '公里',
icon: $r('app.media.ic_distance')
})
}
GridItem() {
MetricCard({
value: this.calories.toString(),
unit: '卡路里',
icon: $r('app.media.ic_calories')
})
}
}
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr')
.columnsGap(12)
.rowsGap(12)
.margin({ bottom: 20 })
// 心率监测
HeartRateMonitor({
currentRate: this.heartRate,
onRateChanged: (rate: number) => {
this.heartRate = rate
}
})
.margin({ bottom: 20 })
// 控制按钮
Button(this.isTracking ? '结束运动' : '开始运动')
.width('80%')
.height(48)
.backgroundColor(this.isTracking ? '#FF5252' : '#4CAF50')
.fontColor(Color.White)
.onClick(() => {
this.isTracking = !this.isTracking
if (this.isTracking) {
this.startTracking()
} else {
this.stopTracking()
}
})
}
.padding(16)
}
private startTracking() {
// 开始计时器
setInterval(() => {
this.timer++
}, 1000)
// 启动传感器
this.sensorManager.enableSensor(sensor.SensorId.STEP_COUNTER)
}
private stopTracking() {
// 保存运动记录
this.saveRecord()
// 停止传感器
this.sensorManager.disableSensor(sensor.SensorId.STEP_COUNTER)
}
private saveRecord() {
const record = {
type: this.currentMotionType,
duration: this.timer,
steps: this.steps,
distance: this.distance,
calories: this.calories,
heartRate: this.heartRate,
date: new Date().toISOString()
}
// 保存到数据库
Database.saveRecord(record)
}
}
3. 运动类型识别组件
// MotionTypeDetector.ets
@Component
export struct MotionTypeDetector {
private motionDetector: motion.MotionDetector = motion.createMotionDetector()
@State detectedType: string = '未知'
aboutToAppear() {
// 初始化运动检测
this.motionDetector.on(motion.MotionType.WALKING, () => {
this.detectedType = '步行'
})
this.motionDetector.on(motion.MotionType.RUNNING, () => {
this.detectedType = '跑步'
})
this.motionDetector.on(motion.MotionType.CYCLING, () => {
this.detectedType = '骑行'
})
this.motionDetector.start()
}
aboutToDisappear() {
this.motionDetector.stop()
}
build() {
Column() {
Text('检测到: ' + this.detectedType)
.fontSize(16)
Image(this.getMotionIcon(this.detectedType))
.width(40)
.height(40)
.margin({ top: 8 })
}
}
private getMotionIcon(type: string): Resource {
switch(type) {
case '步行': return $r('app.media.ic_walking')
case '跑步': return $r('app.media.ic_running')
case '骑行': return $r('app.media.ic_cycling')
default: return $r('app.media.ic_unknown_motion')
}
}
}
4. 历史记录页面
// HistoryPage.ets
@Component
struct HistoryPage {
@State records: Array<MotionRecord> = []
aboutToAppear() {
this.loadRecords()
}
private loadRecords() {
Database.getRecords().then((data) => {
this.records = data
})
}
build() {
List() {
ForEach(this.records, (record) => {
ListItem() {
MotionRecordCard({ record: record })
}
.onClick(() => {
router.push({
url: 'pages/RecordDetailPage',
params: { recordId: record.id }
})
})
})
}
.divider({ strokeWidth: 1, color: '#EEEEEE' })
.edgeEffect(EdgeEffect.Spring)
}
}
5. 健康分析图表
// AnalysisChart.ets
@Component
export struct AnalysisChart {
@State data: Array<{ date: string, value: number }> = []
build() {
Column() {
// 周运动数据图表
Text('本周运动趋势')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.margin({ bottom: 16 })
Chart({
datasets: [
{
data: this.data,
strokeWidth: 2,
gradient: {
colors: ['#6200EE', '#03DAC6'],
direction: GradientDirection.TOP_BOTTOM
}
}
],
xAxis: {
axisTick: 5,
axisLabel: (value: string) => {
return value.substring(5) // 显示简写日期
}
},
yAxis: {
min: 0,
max: Math.max(...this.data.map(item => item.value)) * 1.2,
axisTick: 5
}
})
.width('100%')
.height(200)
.margin({ bottom: 24 })
// 运动类型分布
Text('运动类型分布')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.margin({ bottom: 16 })
PieChart({
data: [
{ value: 45, name: '步行', color: '#4CAF50' },
{ value: 30, name: '跑步', color: '#2196F3' },
{ value: 25, name: '骑行', color: '#FF9800' }
],
showPercentage: true
})
.width(200)
.height(200)
}
.padding(16)
}
}
设计要点
-
传感器集成:
// 传感器管理封装 class SensorService { private static instance: SensorService private sensorManager: sensor.SensorManager private constructor() { this.sensorManager = sensor.getSensorManager() } public static getInstance(): SensorService { if (!SensorService.instance) { SensorService.instance = new SensorService() } return SensorService.instance } public startStepCounter(callback: (steps: number) => void) { const stepCounter = this.sensorManager.getDefaultSensor(sensor.SensorId.STEP_COUNTER) this.sensorManager.on(sensor.SensorId.STEP_COUNTER, (data: sensor.SensorData) => { callback(data.steps) }) this.sensorManager.enableSensor(sensor.SensorId.STEP_COUNTER) } } -
数据持久化:
// 数据库操作封装 import relationalStore from '@ohos.data.relationalStore' class Database { private static STORE_CONFIG = { name: 'MotionTracker.db', securityLevel: relationalStore.SecurityLevel.S1 } private static TABLE_SCHEMA = { tableName: 'records', columns: [ { fieldName: 'id', type: relationalStore.ValueType.INTEGER, isPrimaryKey: true }, { fieldName: 'type', type: relationalStore.ValueType.STRING }, { fieldName: 'duration', type: relationalStore.ValueType.INTEGER }, // 其他字段... ] } static async saveRecord(record: MotionRecord) { const rdbStore = await relationalStore.getRdbStore(this.STORE_CONFIG) await rdbStore.insert(this.TABLE_SCHEMA.tableName, record) } } -
性能优化:
// 使用Worker处理传感器数据 const worker = new Worker('workers/SensorWorker.ts') worker.onmessage = (message) => { // 处理传感器数据 } // 在Worker中 const sensorManager = sensor.getSensorManager() sensorManager.on(sensor.SensorId.STEP_COUNTER, (data) => { workerPort.postMessage(data) }) -
权限管理:
// 检查并请求必要权限 import abilityAccessCtrl from '@ohos.abilityAccessCtrl' async function checkPermissions() { const atManager = abilityAccessCtrl.createAtManager() try { const permissions = [ 'ohos.permission.HEALTH_DATA', 'ohos.permission.ACTIVITY_MOTION' ] const result = await atManager.requestPermissionsFromUser(permissions) return result.granted.every(granted => granted) } catch (err) { console.error('权限请求失败:', err) return false } }
总结
通过HarmonyOS 5的运动健康服务能力和ArkUI框架,我们实现了一个功能全面的运动检测应用,具有以下特点:
- 多维度运动监测:实时跟踪步数、距离、卡路里、心率等数据
- 智能运动识别:自动识别步行、跑步、骑行等运动类型
- 数据可视化:通过图表展示运动趋势和健康分析
- 历史记录:完整记录每次运动数据,支持详情查看
- 权限与安全:完善的权限管理和数据保护机制
该应用充分利用了HarmonyOS的传感器能力、分布式技术和UI框架,为用户提供了专业级的运动监测体验,同时符合HarmonyOS Design的设计规范,确保良好的用户体验。
更多推荐


所有评论(0)