代碼功能概述
這段代碼實現了一個功能完整的鴻蒙健康計步器應用,全面展示了ArkTS在傳感器數據獲取、數據持久化、圖表展示和健康算法計算等方面的核心能力。主要功能包括:
- 實時步數監測:模擬獲取用户行走步數,實時更新顯示
- 健康數據統計:計算消耗卡路里、行走距離、運動時間等健康指標
- 目標進度追蹤:設置每日步數目標,顯示完成進度
- 歷史數據圖表:使用柱狀圖展示最近7天的步數趨勢
- 數據持久化存儲:模擬本地存儲健康數據,支持歷史記錄查詢
- 智能提醒功能:根據運動狀態提供健康建議和提醒
通過這個示例,可以深入理解ArkTS如何實現傳感器數據處理、圖表可視化和健康算法計算。
2. 代碼邏輯分析
應用採用"多狀態驅動UI"的複雜架構設計:
- 初始化階段:應用啓動時,通過aboutToAppear()生命週期方法加載歷史數據和初始化傳感器
- 狀態管理:使用多個@State裝飾器管理步數數據、健康指標、歷史記錄和用户設置
- 實時數據流:
- 模擬傳感器數據 → 更新當前步數 → 重新計算健康指標
- 數據變化 → 自動保存到本地存儲 → 更新圖表顯示
- 用户交互流程:
- 點擊重置按鈕 → 清零當日步數 → 重新開始統計
- 修改目標設置 → 更新進度計算 → 刷新界面顯示
- 查看歷史記錄 → 切換數據顯示 → 更新圖表內容
- 智能計算:基於步數自動計算卡路里、距離、時間等衍生健康數據
完整代碼
// 數據模型定義
class StepData {
date: string = '';
steps: number = 0;
calories: number = 0;
distance: number = 0;
}
class UserSettings {
goal: number = 10000;
weight: number = 70; // 默認體重70kg
strideLength: number = 0.7; // 默認步幅0.7米
}
@Entry
@Component
struct StepCounterTutorial {
// 狀態管理變量
@State currentSteps: number = 0;
@State dailyGoal: number = 10000;
@State caloriesBurned: number = 0;
@State distanceWalked: number = 0;
@State activeTime: number = 0;
@State isTracking: boolean = true;
@State currentDate: string = '';
@State stepHistory: StepData[] = [];
@State showHistory: boolean = false;
// 生命週期函數
aboutToAppear() {
this.initializeStepCounter();
this.startStepTracking();
this.loadHistoricalData();
}
// 初始化計步器
initializeStepCounter() {
// 設置當前日期
const now = new Date();
this.currentDate = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
// 初始化健康指標
this.calculateHealthMetrics();
}
// 啓動步數跟蹤
startStepTracking() {
// 模擬傳感器數據更新
setInterval(() => {
if (this.isTracking) {
// 模擬步數增加
this.currentSteps += Math.floor(Math.random() * 10);
this.calculateHealthMetrics();
this.saveCurrentData();
}
}, 3000);
}
// 計算健康指標
calculateHealthMetrics() {
// 計算卡路里 (步數 * 0.04 * 體重kg)
this.caloriesBurned = Math.round(this.currentSteps * 0.04 * 70);
// 計算距離 (步數 * 步幅 / 1000)
this.distanceWalked = parseFloat((this.currentSteps * 0.7 / 1000).toFixed(2));
// 計算活躍時間 (步數 / 100 * 10分鐘)
this.activeTime = Math.round(this.currentSteps / 100 * 10);
}
// 加載歷史數據
loadHistoricalData() {
// 模擬加載歷史數據
for (let i = 6; i >= 0; i--) {
const date = new Date();
date.setDate(date.getDate() - i);
const dateStr = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
this.stepHistory.push({
date: dateStr,
steps: Math.floor(Math.random() * 15000),
calories: Math.floor(Math.random() * 600),
distance: parseFloat((Math.random() * 10).toFixed(2))
});
}
}
// 保存當前數據
saveCurrentData() {
// 模擬數據持久化
console.log('保存數據:', {
steps: this.currentSteps,
calories: this.caloriesBurned,
distance: this.distanceWalked
});
}
// 重置步數
resetSteps() {
this.currentSteps = 0;
this.calculateHealthMetrics();
}
// 切換歷史視圖
toggleHistoryView() {
this.showHistory = !this.showHistory;
}
// 主構建函數
build() {
Column({ space: 0 }) {
// 應用標題和日期
this.BuildHeader()
// 主要數據展示
if (this.showHistory) {
this.BuildHistoryView()
} else {
this.BuildMainDashboard()
}
// 底部導航
this.BuildNavigation()
}
.width('100%')
.height('100%')
.backgroundColor('#F5F7FA')
}
// 頂部標題構建函數
@Builder BuildHeader() {
Column({ space: 10 }) {
Text('健康計步器')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor('#2D3748')
Text(this.currentDate)
.fontSize(16)
.fontColor('#718096')
// 目標進度條
this.BuildGoalProgress()
}
.width('100%')
.padding(20)
.backgroundColor('#FFFFFF')
.shadow({ radius: 2, color: '#000000', offsetX: 0, offsetY: 1 })
}
// 目標進度構建函數
@Builder BuildGoalProgress() {
const progress = Math.min(this.currentSteps / this.dailyGoal, 1);
Column({ space: 8 }) {
Row({ space: 10 }) {
Text('每日目標')
.fontSize(14)
.fontColor('#4A5568')
.layoutWeight(1)
Text(`${this.currentSteps} / ${this.dailyGoal}`)
.fontSize(14)
.fontColor('#2D3748')
.fontWeight(FontWeight.Medium)
}
// 進度條背景
Stack() {
// 背景軌道
Rect()
.width('100%')
.height(8)
.fill('#E2E8F0')
.borderRadius(4)
// 進度填充
Rect()
.width(`${progress * 100}%`)
.height(8)
.fill(progress >= 1 ? '#48BB78' : '#4299E1')
.borderRadius(4)
}
.width('100%')
.height(8)
}
.width('100%')
.margin({ top: 10 })
}
// 主儀表盤構建函數
@Builder BuildMainDashboard() {
Column({ space: 20 }) {
// 步數環形進度
this.BuildStepCircle()
// 健康數據統計
this.BuildHealthStats()
// 控制按鈕
this.BuildControlButtons()
}
.width('100%')
.padding(20)
.layoutWeight(1)
}
// 步數環形進度構建函數
@Builder BuildStepCircle() {
const progress = Math.min(this.currentSteps / this.dailyGoal, 1);
const circumference = 2 * Math.PI * 80; // 環形周長
Stack({ alignContent: Alignment.Center }) {
// 背景環
Circle({ width: 180, height: 180 })
.fill('#FFFFFF')
.stroke('#E2E8F0')
.strokeWidth(12)
// 進度環
Circle({ width: 180, height: 180 })
.fill(Color.Transparent)
.stroke(progress >= 1 ? '#48BB78' : '#4299E1')
.strokeWidth(12)
.strokeDashArray(`${circumference}`)
.strokeDashOffset(`${circumference * (1 - progress)}`)
// 中心文本
Column({ space: 5 }) {
Text(this.currentSteps.toString())
.fontSize(36)
.fontWeight(FontWeight.Bold)
.fontColor('#2D3748')
Text('步')
.fontSize(16)
.fontColor('#718096')
}
}
.width(200)
.height(200)
}
// 健康統計構建函數
@Builder BuildHealthStats() {
Grid() {
GridItem() {
this.BuildStatItem('🔥', '卡路里', `${this.caloriesBurned} kcal`)
}
GridItem() {
this.BuildStatItem('👣', '距離', `${this.distanceWalked} km`)
}
GridItem() {
this.BuildStatItem('⏱️', '時間', `${this.activeTime} 分鐘`)
}
GridItem() {
this.BuildStatItem('🎯', '完成度', `${Math.round((this.currentSteps / this.dailyGoal) * 100)}%`)
}
}
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr')
.columnsGap(15)
.rowsGap(15)
.width('100%')
}
// 統計項構建函數
@Builder BuildStatItem(icon: string, label: string, value: string) {
Column({ space: 8 }) {
Text(icon)
.fontSize(24)
Text(label)
.fontSize(12)
.fontColor('#718096')
Text(value)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('#2D3748')
}
.width('100%')
.padding(15)
.backgroundColor('#FFFFFF')
.borderRadius(12)
.shadow({ radius: 2, color: '#000000', offsetX: 0, offsetY: 1 })
}
// 控制按鈕構建函數
@Builder BuildControlButtons() {
Row({ space: 15 }) {
Button('重置步數')
.fontSize(16)
.fontColor('#FFFFFF')
.backgroundColor('#E53E3E')
.borderRadius(25)
.width(120)
.height(45)
.onClick(() => {
this.resetSteps()
})
Button('暫停/繼續')
.fontSize(16)
.fontColor(this.isTracking ? '#2D3748' : '#FFFFFF')
.backgroundColor(this.isTracking ? '#E2E8F0' : '#4299E1')
.borderRadius(25)
.width(120)
.height(45)
.onClick(() => {
this.isTracking = !this.isTracking
})
}
.width('100%')
.justifyContent(FlexAlign.Center)
}
// 歷史視圖構建函數
@Builder BuildHistoryView() {
Column({ space: 20 }) {
Text('最近7天步數趨勢')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#2D3748')
.width('100%')
.textAlign(TextAlign.Start)
// 柱狀圖容器
Column({ space: 10 }) {
ForEach(this.stepHistory, (item: StepData, index: number) => {
this.BuildHistoryBar(item, index)
})
}
.width('100%')
.height(300)
.padding(20)
.backgroundColor('#FFFFFF')
.borderRadius(12)
.shadow({ radius: 2, color: '#000000', offsetX: 0, offsetY: 1 })
}
.width('100%')
.padding(20)
.layoutWeight(1)
}
// 歷史數據柱狀圖構建函數
@Builder BuildHistoryBar(item: StepData, index: number) {
const maxSteps = Math.max(...this.stepHistory.map(data => data.steps));
const heightPercent = (item.steps / maxSteps) * 100;
Row({ space: 15 }) {
Text(item.date.split('-').slice(1, 3).join('/'))
.fontSize(12)
.fontColor('#718096')
.width(60)
// 柱狀圖
Stack({ alignContent: Alignment.BottomStart }) {
// 背景
Rect()
.width(30)
.height(150)
.fill('#E2E8F0')
.borderRadius(4)
// 數據柱
Rect()
.width(30)
.height(`${heightPercent}%`)
.fill('#4299E1')
.borderRadius(4)
}
.width(30)
.height(150)
Column({ space: 2 }) {
Text(item.steps.toString())
.fontSize(14)
.fontWeight(FontWeight.Medium)
.fontColor('#2D3748')
Text('步')
.fontSize(10)
.fontColor('#718096')
}
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.height(60)
}
// 底部導航構建函數
@Builder BuildNavigation() {
Row({ space: 0 }) {
Button('今日數據')
.fontSize(16)
.fontColor(this.showHistory ? '#718096' : '#4299E1')
.backgroundColor(Color.Transparent)
.width('50%')
.height(50)
.onClick(() => {
this.showHistory = false
})
Button('歷史記錄')
.fontSize(16)
.fontColor(this.showHistory ? '#4299E1' : '#718096')
.backgroundColor(Color.Transparent)
.width('50%')
.height(50)
.onClick(() => {
this.showHistory = true
})
}
.width('100%')
.backgroundColor('#FFFFFF')
.shadow({ radius: 2, color: '#000000', offsetX: 0, offsetY: -1 })
}
}
想入門鴻蒙開發又怕花冤枉錢?別錯過!現在能免費系統學 -- 從 ArkTS 面向對象核心的類和對象、繼承多態,到吃透鴻蒙開發關鍵技能,還能衝刺鴻蒙基礎 +高級開發者證書,更驚喜的是考證成功還送好禮!快加入我的鴻蒙班,一起從入門到精通,班級鏈接:點擊免費進入