📡 零基础学 ArkUI 传感器(专题二):从加速度计到指南针,玩转硬件能力
博主说:你的手机里藏着十几个传感器——加速度计、陀螺仪、地磁、光线、距离、气压……在 ArkUI 中调用它们只需要几行代码!今天这篇专题带你一次摸透 HarmonyOS 的传感器全家桶,并实战做一个「水平仪」和「电子罗盘」。
📱 传感器能做什么?
| 传感器 | 检测什么 | 应用场景 |
|---|---|---|
加速度计ACCELEROMETER | 三轴加速度 | 计步器、摇一摇、屏幕旋转 |
陀螺仪GYROSCOPE | 角速度 | VR 头显、体感游戏 |
地磁MAGNETIC_FIELD | 磁场强度 | 电子罗盘、指南针 |
环境光AMBIENT_LIGHT | 光照强度 lux | 自动亮度调节 |
距离PROXIMITY | 物体靠近 | 通话熄屏 |
气压BAROMETER | 大气压力 | 海拔测量 |
心率HEART_RATE | 心跳 | 健康监测 |
⚙️ 运行环境要求
| 项目 | 要求 |
|---|---|
| 设备要求 | 真机!(模拟器不支持传感器) |
| DevEco Studio | 5.0.3.800+ |
| HarmonyOS SDK | API 12+ |
| 核心 API | @ohos.sensor |
🛠️ 4 个实战案例
🎯 案例 1:加速度计 — 做一个「摇一摇」检测
importsensorfrom'@ohos.sensor';@Entry@Componentstruct ShakeDetector{@StateshakeCount:number=0;@StatelastShakeTime:number=0;@StateisShaking:boolean=false;aboutToAppear(){this.startListening();}startListening(){sensor.on(sensor.SensorType.ACCELEROMETER,(data)=>{// 计算三轴加速度的矢量和constx=data.x;consty=data.y;constz=data.z;constmagnitude=Math.sqrt(x*x+y*y+z*z);// 加速度 > 15 m/s² 视为一次摇动(重力 ≈ 9.8)if(magnitude>15){constnow=Date.now();if(now-this.lastShakeTime>500){// 500ms 内只算一次this.lastShakeTime=now;this.shakeCount++;this.isShaking=true;// 300ms 后取消摇动状态setTimeout(()=>{this.isShaking=false;},300);}}});}build(){Column(){Text(this.isShaking?'📳 正在摇动!':'📱 摇动手机').fontSize(24).fontWeight(FontWeight.Bold).fontColor(this.isShaking?'#FF3B30':'#333')Text(`已摇动${this.shakeCount}次`).fontSize(16).fontColor('#888').margin({top:12})Button('重置计数').margin({top:20}).backgroundColor('#E5E5EA').fontColor('#333').onClick(()=>{this.shakeCount=0;})}.width('100%').height(200).justifyContent(FlexAlign.Center)}}核心 API 说明:
// 订阅传感器数据(持续监听)sensor.on(SensorType.ACCELEROMETER,callback);// 取消订阅sensor.off(SensorType.ACCELEROMETER,callback);// 单次读取sensor.once(SensorType.ACCELEROMETER,(data)=>{});真机运行:用力摇动手机,屏幕显示摇动次数。
🎯 案例 2:陀螺仪 — 体感控制的旋转方块
importsensorfrom'@ohos.sensor';@Entry@Componentstruct GyroCube{@StaterotateX:number=0;@StaterotateY:number=0;@StaterotateZ:number=0;aboutToAppear(){sensor.on(sensor.SensorType.GYROSCOPE,(data)=>{// 积分角速度得到角度this.rotateX+=data.x*0.1;this.rotateY+=data.y*0.1;this.rotateZ+=data.z*0.1;});}build(){Column(){Column(){Text('3D').fontSize(32).fontColor('#fff').fontWeight(FontWeight.Bold)}.width(120).height(120).backgroundColor('#007AFF').borderRadius(16).rotate({x:1,angle:this.rotateX}).rotate({y:1,angle:this.rotateY})Text('转动手机控制方块旋转').fontSize(14).fontColor('#999').margin({top:20})}.width('100%').height(300).justifyContent(FlexAlign.Center)}}🎯 案例 3:地磁传感器 — 电子指南针
importsensorfrom'@ohos.sensor';@Entry@Componentstruct Compass{@Stateheading:number=0;// 0~360 度aboutToAppear(){sensor.on(sensor.SensorType.MAGNETIC_FIELD,(data)=>{// 根据地磁三轴数据计算方位角constheading=Math.atan2(data.y,data.x)*180/Math.PI;this.heading=(heading+360)%360;// 转为 0~360});}getDirection(degree:number):string{if(degree<22.5||degree>=337.5)return'北 ↑';if(degree<67.5)return'东北 ↗';if(degree<112.5)return'东 →';if(degree<157.5)return'东南 ↘';if(degree<202.5)return'南 ↓';if(degree<247.5)return'西南 ↙';if(degree<292.5)return'西 ←';return'西北 ↖';}build(){Column(){// 指南针表盘Circle().width(200).height(200).fill('#F0F4FF').stroke('#007AFF').strokeWidth(3)Text('N').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#FF3B30').position({x:100,y:10})// 指针Column().width(4).height(80).backgroundColor('#FF3B30').borderRadius(2).rotate({angle:this.heading})// 度数显示Text(`${Math.round(this.heading)}°`).fontSize(36).fontWeight(FontWeight.Bold).fontColor('#333').margin({top:20})Text(this.getDirection(this.heading)).fontSize(18).fontColor('#007AFF').margin({top:8})}.width('100%').height(400).justifyContent(FlexAlign.Center)}}🎯 案例 4:综合实战 — 水平仪 App
结合加速度计和陀螺仪,做一个气泡水平仪。
importsensorfrom'@ohos.sensor';@Entry@Componentstruct BubbleLevel{@StatebubbleX:number=0;@StatebubbleY:number=0;@StateisLevel:boolean=true;aboutToAppear(){sensor.on(sensor.SensorType.ACCELEROMETER,(data)=>{// 手机平放时,重力在 Z 轴 = 9.8,X/Y ≈ 0// X/Y 偏离 0 说明手机倾斜constthreshold=0.5;this.bubbleX=Math.max(-40,Math.min(40,-data.x*8));this.bubbleY=Math.max(-40,Math.min(40,data.y*8));this.isLevel=Math.abs(data.x)<threshold&&Math.abs(data.y)<threshold;});}build(){Column(){Text(this.isLevel?'✅ 水平':'❌ 倾斜').fontSize(32).fontWeight(FontWeight.Bold).fontColor(this.isLevel?'#34C759':'#FF3B30')// 水平仪容器Stack(){// 外圈Circle().width(200).height(200).fill('#F0F4FF').stroke('#007AFF').strokeWidth(2)// 十字线Divider().vertical(true).height(180).color('#E0E0E0')Divider().width(180).color('#E0E0E0')// 气泡Circle().width(24).height(24).fill('#007AFF').opacity(0.7).translate({x:this.bubbleX,y:this.bubbleY})}.width(220).height(220).margin({top:20})Text(`偏移: X=${this.bubbleX.toFixed(1)}Y=${this.bubbleY.toFixed(1)}`).fontSize(14).fontColor('#999').margin({top:16})}.width('100%').height(400).justifyContent(FlexAlign.Center)}}📊 传感器数据对比表
| 传感器 | 回调频率 | 数据维度 | 坐标系 |
|---|---|---|---|
| ACCELEROMETER | 50~200Hz | x, y, z (m/s²) | 设备坐标系 |
| GYROSCOPE | 50~200Hz | x, y, z (rad/s) | 设备坐标系 |
| MAGNETIC_FIELD | 10~50Hz | x, y, z (μT) | 设备坐标系 |
| AMBIENT_LIGHT | 1~10Hz | intensity (lux) | 单值 |
| PROXIMITY | 1~5Hz | distance (cm) | 单值 |
⚠️ 避坑指南
| 坑 | 原因 | 正确做法 |
|---|---|---|
| 模拟器传感器没数据 | 模拟器没有硬件 | 必须用真机调试 |
| 传感器不触发回调 | 忘了sensor.on()订阅 | 在aboutToAppear中订阅 |
| 数据跳变太大 | 原始传感器噪声大 | 用滑动平均滤波(取最近 5 次均值) |
| 陀螺仪角度飘移 | 积分累积误差 | 用地磁 + 加速度计做互补滤波 |
| 耗电快 | 传感器回调频率太高 | 不需要高频率时用sensor.once() |
| 后台不工作 | 传感器在后台被暂停 | 申请后台任务权限 |
🔥 最佳实践
- 滤波处理:原始传感器噪声大,用低通滤波或滑动平均
- 频率控制:不需要高频率时用
setInterval节流回调 - 真机调试:传感器开发必须真机,模拟器不支持
- 性能优化:
aboutToDisappear中取消订阅,防止内存泄漏 - 权限申明:部分传感器(心率等)需要
health权限 - 传感器融合:结合加速度 + 陀螺仪 + 地磁得到更准确的姿态
🚀 扩展挑战
- 计步器:用加速度计检测步行步态(峰值检测算法)
- 手势识别:用陀螺仪识别「画圈」「挥动」等手势
- AR 水平仪:结合相机预览 + 水平仪做装修辅助工具
- 磁力计标定:用「画 8 字」方法校准地磁传感器
官方文档:HarmonyOS 应用开发文档
- 开发者社区:华为开发者论坛
- 欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net/