HarmonyOS鸿蒙Next应用实现手机摇一摇功能,请提供详细步骤和源码

HarmonyOS鸿蒙Next应用实现手机摇一摇功能,请提供详细步骤和源码

鸿蒙应用实现手机摇一摇功能,请提供详细步骤和源码

1. 实现原理

在鸿蒙应用中,可以通过加速度传感器来检测手机的摇晃动作。当用户在短时间内快速摇晃手机时,加速度传感器会检测到加速度的快速变化,从而触发摇一摇事件。

2. 开发步骤

2.1 创建新项目

  1. 打开DevEco Studio
  2. 选择"Create HarmonyOS Project"
  3. 选择"Empty Ability"模板
  4. 配置项目名称、包名等信息

2.2 配置权限

config.json文件中添加传感器权限:

{
  "module": {
    "reqPermissions": [
      {
        "name": "ohos.permission.ACCELEROMETER"
      }
    ]
  }
}

2.3 创建摇一摇工具类

package com.example.shakedemo.utils;

import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.sensor.agent.CategoryOrientationAgent;
import ohos.sensor.bean.SensorBean;
import ohos.sensor.listener.ICategoryOrientationDataCallback;

import java.util.List;

public class ShakeDetector {
    private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00201, "ShakeDetector");
    
    // 传感器代理
    private CategoryOrientationAgent orientationAgent;
    
    // 回调接口
    private OnShakeListener onShakeListener;
    
    // 上次检测时间
    private long lastUpdateTime;
    
    // 上次的加速度值
    private float lastX, lastY, lastZ;
    
    // 阈值
    private static final int SHAKE_THRESHOLD = 2000;
    private static final int UPDATE_INTERVAL = 100;
    
    public interface OnShakeListener {
        void onShake();
    }
    
    public ShakeDetector() {
        orientationAgent = new CategoryOrientationAgent();
    }
    
    public void setOnShakeListener(OnShakeListener listener) {
        this.onShakeListener = listener;
    }
    
    public void start() {
        List<SensorBean> sensorList = orientationAgent.getAllSensors();
        if (sensorList.isEmpty()) {
            HiLog.error(LABEL, "No orientation sensor found");
            return;
        }
        
        int sensorId = sensorList.get(0).getSensorId();
        
        ICategoryOrientationDataCallback callback = new ICategoryOrientationDataCallback() {
            @Override
            public void onSensorDataModified(CategoryOrientationAgent.CategoryOrientationData data) {
                detectShake(data.values);
            }
            
            @Override
            public void onAccuracyDataModified(CategoryOrientationAgent.CategoryOrientationData data, int accuracy) {
                // 精度变化处理
            }
            
            @Override
            public void onCommandCompleted(CategoryOrientationAgent.CategoryOrientationData data) {
                // 命令完成处理
            }
        };
        
        orientationAgent.setSensorDataCallback(callback, sensorId, CategoryOrientationAgent.SENSOR_SAMPLE_RATE_FASTEST);
    }
    
    public void stop() {
        orientationAgent.releaseSensorDataCallback();
    }
    
    private void detectShake(float[] values) {
        long currentTime = System.currentTimeMillis();
        long timeInterval = currentTime - lastUpdateTime;
        
        if (timeInterval < UPDATE_INTERVAL) {
            return;
        }
        
        lastUpdateTime = currentTime;
        
        float x = values[0];
        float y = values[1];
        float z = values[2];
        
        float deltaX = x - lastX;
        float deltaY = y - lastY;
        float deltaZ = z - lastZ;
        
        lastX = x;
        lastY = y;
        lastZ = z;
        
        double speed = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) / timeInterval * 10000;
        
        if (speed > SHAKE_THRESHOLD) {
            if (onShakeListener != null) {
                onShakeListener.onShake();
            }
        }
    }
}

2.4 在主页面中使用

package com.example.shakedemo.slice;

import com.example.shakedemo.ResourceTable;
import com.example.shakedemo.utils.ShakeDetector;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Text;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

public class MainAbilitySlice extends AbilitySlice {
    private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MainAbilitySlice");
    
    private Text shakeText;
    private ShakeDetector shakeDetector;
    
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);
        
        initComponents();
        initShakeDetector();
    }
    
    private void initComponents() {
        shakeText = (Text) findComponentById(ResourceTable.Id_shake_text);
    }
    
    private void initShakeDetector() {
        shakeDetector = new ShakeDetector();
        shakeDetector.setOnShakeListener(() -> {
            getUITaskDispatcher().asyncDispatch(() -> {
                shakeText.setText("检测到摇一摇动作!");
                HiLog.info(LABEL, "Shake detected!");
                
                // 3秒后恢复原文本
                getUITaskDispatcher().delayDispatch(() -> {
                    shakeText.setText("请摇晃手机");
                }, 3000);
            });
        });
    }
    
    @Override
    protected void onActive() {
        super.onActive();
        shakeDetector.start();
        shakeText.setText("请摇晃手机");
    }
    
    @Override
    protected void onInactive() {
        super.onInactive();
        shakeDetector.stop();
    }
    
    @Override
    protected void onBackground() {
        super.onBackground();
        shakeDetector.stop();
    }
}

2.5 布局文件

resources/base/layout/ability_main.xml中添加:

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:width="match_parent"
    ohos:height="match_parent"
    ohos:alignment="center"
    ohos:orientation="vertical">
    
    <Text
        ohos:id="$+id:shake_text"
        ohos:width="match_content"
        ohos:height="match_content"
        ohos:text="请摇晃手机"
        ohos:text_size="24fp"
        ohos:text_alignment="center"
        ohos:margin="20vp"/>
        
</DirectionalLayout>

3. 关键点说明

3.1 传感器权限

必须先在config.json中声明加速度传感器权限,否则无法获取传感器数据。

3.2 传感器回调

通过ICategoryOrientationDataCallback接口接收传感器数据,在onSensorDataModified方法中处理加速度数据。

3.3 摇动检测算法

通过计算三个方向加速度的变化率来判断是否发生摇动。当变化率超过设定的阈值时,触发摇一摇事件。

3.4 性能优化

  • 设置合适的数据采样率
  • 添加时间间隔检测,避免频繁处理
  • 在页面不可见时停止传感器监听

4. 扩展功能建议

  1. 灵敏度调节:可以添加设置界面,让用户调节摇动灵敏度
  2. 声音反馈:摇动时播放提示音
  3. 振动反馈:摇动时触发手机振动
  4. 防误触:添加时间间隔限制,避免连续触发

5. 注意事项

  1. 确保在真机上测试,模拟器可能无法模拟传感器数据
  2. 注意权限申请流程
  3. 及时释放传感器资源,避免电量消耗
  4. 考虑不同设备的传感器差异

以上代码提供了完整的鸿蒙应用摇一摇功能实现,可以直接在项目中集成使用。


更多关于HarmonyOS鸿蒙Next应用实现手机摇一摇功能,请提供详细步骤和源码的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

一、结论

手机摇一摇功能,是通过获取手机设备,加速度传感器接口,获取其中的数值,进行逻辑判断实现的功能。

鸿蒙中手机设备传感器@ohos.sensor (传感器)的系统API监听有以下: [@ohos.sensor (传感器)官网API](https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-sensor-V5#accelerometer9)

  1. 加速度传感器
  2. 环境光传感器
  3. 气压计传感器
  4. 重力传感器
  5. 陀螺仪传感器
  6. 霍尔传感器
  7. 心率传感器
  8. 湿度传感器
  9. 线性加速度传感器
  10. 地磁传感器
  11. 方向传感器
  12. 计步器传感器
  13. 接近光传感器
  14. 旋转矢量传感器
  15. 大幅动作检测传感器
  16. 佩戴检测传感器

其中摇一摇用到的,加速度传感器是多个维度测算的,是指x、y、z三个方向上的加速度值。 主要测算一些瞬时加速或减速的动作。比如测量手机的运动速度和方向。

cke_806.png

当用户拿着手机运动时,会出现上下摆动的情况,这样可以检测出加速度在某个方向上来回改变,通过检测这个来回改变的次数,可以计算出步数。

在游戏里能通过加速度传感器触发特殊指令。日常应用中的一些甩动切歌、翻转静音等也都用到了这枚传感器。

注意: 至于为什么不用线性加速传感器,是因为线性加速度传感器和加速度传感器在定义、工作原理以及应用场景上存在显著的区别。线性主要是来检测物体在直线方向上的位移。

二、代码实现和详细解释

1.根据通过@ohos.sensor接口,获取加速度传感器的数值,添加权限:ohos.permission.ACCELEROMETER

{
        "name": "ohos.permission.ACCELEROMETER",
        "reason": "$string:reason",
        "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          "when": "always"
        }
      }
 sensor.on(sensor.SensorId.ACCELEROMETER, (data: sensor.AccelerometerResponse) => {

      }, { interval: 100000000 }); // 设置间隔为100000000 ns  = 0.1 s

2.将x,y,z三个方向的数值进行绝对值处理,获取运动数值

 sensor.on(sensor.SensorId.ACCELEROMETER, (data: sensor.AccelerometerResponse) => {
       console.info(this.TAG, 'Succeeded in invoking on. X-coordinate component: ' + data.x);
        console.info(this.TAG,'Succeeded in invoking on. Y-coordinate component: ' + data.y);
        console.info(this.TAG,'Succeeded in invoking on. Z-coordinate component: ' + data.z);
      }, { interval: 100000000 }); // 设置间隔为100000000 ns  = 0.1 s

3.根据运动数值进行判断,是否符合摇一摇的运动区间

        let x = Math.abs(data.x);
        let y = Math.abs(data.y);
        let z  = Math.abs(data.z);

        this.message = "x : " + x + "  y: " +  y + " z: " + z;
        if(x > this.SWING_VAL || y > this.SWING_VAL || z > this.SWING_VAL){
          promptAction.showToast({
            message: "手机正在摇一摇!"
          })
        }

最后一步,当然就是使用手机设备进行代码功能效果的验证。 若没有真机设备,使用模拟器,点击该按钮可实现摇一摇手机的触发。

cke_2226.png

注意: 不使用加速传感器时,一定要移除监听。否则会白白损耗性能。

三、源码示例:

cke_4388.png

import { sensor } from '@kit.SensorServiceKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { promptAction } from '@kit.ArkUI';

@Entry
@Component
struct SensorTestPage {

  private TAG: string = "SenorTestPage";
  private SWING_VAL: number = 50;

  @State message: string = '';

  aboutToAppear(): void {
    try {
      // 订阅加速度传感器返回的数据
      sensor.on(sensor.SensorId.ACCELEROMETER, (data: sensor.AccelerometerResponse) => {

        console.info(this.TAG, 'Succeeded in invoking on. X-coordinate component: ' + data.x);
        console.info(this.TAG,'Succeeded in invoking on. Y-coordinate component: ' + data.y);
        console.info(this.TAG,'Succeeded in invoking on. Z-coordinate component: ' + data.z);

        let x = Math.abs(data.x);
        let y = Math.abs(data.y);
        let z  = Math.abs(data.z);

        this.message = "x : " + x + "  y: " +  y + " z: " + z;
        if(x > this.SWING_VAL || y > this.SWING_VAL || z > this.SWING_VAL){
          promptAction.showToast({
            message: "手机正在摇一摇!"
          })
        }

      }, { interval: 100000000 }); // 设置间隔为100000000 ns  = 0.1 s

    } catch (error) {
      let e: BusinessError = error as BusinessError;
      console.error(this.TAG, `Failed to invoke on. Code: ${e.code}, message: ${e.message}`);
    }
  }

  aboutToDisappear(): void {
    sensor.off(sensor.SensorId.ACCELEROMETER);
  }

  build() {
    RelativeContainer() {
      Text(this.message)
        .id('SenorTestPageHelloWorld')
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
    }
    .height('100%')
    .width('100%')
  }
}

注意: 记得添加ohos.permission.ACCELEROMETER权限,否则无法监听到加速传感器!

更多关于HarmonyOS鸿蒙Next应用实现手机摇一摇功能,请提供详细步骤和源码的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


鸿蒙Next中实现摇一摇功能主要使用传感器模块。以下是核心步骤与代码片段:

  1. module.json5中申请ohos.permission.ACCELEROMETER权限。
  2. 在页面中导入传感器模块:import sensor from '@ohos.sensor';
  3. 监听加速度传感器数据,计算设备晃动幅度。

关键源码示例(ArkTS):

import sensor from '@ohos.sensor';

// 注册加速度传感器监听
sensor.on(sensor.SensorId.ACCELEROMETER, (data) => {
  // 计算加速度变化量,判断是否达到摇动阈值
  let speed = Math.abs(data.x + data.y + data.z - lastX - lastY - lastZ) / diffTime * 10000;
  if (speed > SHAKE_THRESHOLD) {
    // 触发摇一摇逻辑
    console.log('摇一摇成功');
  }
  // 更新上一次的加速度值
  [lastX, lastY, lastZ] = [data.x, data.y, data.z];
});
  1. 在适当时机调用sensor.off()取消监听。

在HarmonyOS Next中实现摇一摇功能,主要通过加速度传感器监听设备加速度变化来判断。以下是关键步骤和示例代码:

1. 权限配置module.json5文件中添加传感器权限:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.ACCELEROMETER"
      }
    ]
  }
}

2. 核心实现代码

import { sensor } from '@kit.SensorServiceKit';
import { BusinessError } from '@kit.BasicServicesKit';

export class ShakeDetector {
  private sensorId: number = -1;
  private lastUpdateTime: number = 0;
  private lastX: number = 0;
  private lastY: number = 0;
  private lastZ: number = 0;
  private readonly SHAKE_THRESHOLD = 15; // 摇动阈值
  private readonly TIME_THRESHOLD = 100; // 时间间隔阈值(ms)

  // 开始监听摇动
  startDetection(callback: () => void): void {
    try {
      const sensorType = sensor.SensorType.SENSOR_TYPE_ACCELEROMETER;
      const options: sensor.SensorOptions = {
        interval: sensor.SensorFrequency.SENSOR_DELAY_FASTEST
      };

      this.sensorId = sensor.on(sensorType, options, (data: sensor.AccelerometerResponse) => {
        this.handleSensorData(data, callback);
      });
    } catch (error) {
      const err: BusinessError = error as BusinessError;
      console.error(`Failed to start sensor: ${err.code} ${err.message}`);
    }
  }

  // 处理传感器数据
  private handleSensorData(data: sensor.AccelerometerResponse, callback: () => void): void {
    const currentTime = new Date().getTime();
    const timeDiff = currentTime - this.lastUpdateTime;

    if (timeDiff > this.TIME_THRESHOLD) {
      const x = data.x;
      const y = data.y;
      const z = data.z;

      const speed = Math.abs(x + y + z - this.lastX - this.lastY - this.lastZ) / timeDiff * 10000;

      if (speed > this.SHAKE_THRESHOLD) {
        callback(); // 触发摇动回调
      }

      this.lastX = x;
      this.lastY = y;
      this.lastZ = z;
      this.lastUpdateTime = currentTime;
    }
  }

  // 停止监听
  stopDetection(): void {
    if (this.sensorId !== -1) {
      sensor.off(sensor.SensorType.SENSOR_TYPE_ACCELEROMETER, this.sensorId);
      this.sensorId = -1;
    }
  }
}

3. 在页面中使用

import { ShakeDetector } from './ShakeDetector';

@Entry
@Component
struct ShakePage {
  private shakeDetector = new ShakeDetector();

  aboutToAppear(): void {
    this.shakeDetector.startDetection(() => {
      // 摇动后执行的逻辑
      console.log('Shake detected!');
      // 可以在这里触发UI更新或其他业务逻辑
    });
  }

  aboutToDisappear(): void {
    this.shakeDetector.stopDetection();
  }

  build() {
    Column() {
      Text('摇动手机试试')
        .fontSize(20)
        .margin(20)
    }
    .width('100%')
    .height('100%')
  }
}

关键说明:

  1. 使用@kit.SensorServiceKit中的加速度传感器API
  2. 通过计算三维加速度变化率判断摇动手势
  3. SHAKE_THRESHOLDTIME_THRESHOLD参数可根据实际需求调整灵敏度
  4. 注意在页面生命周期中正确管理传感器的注册和注销

此实现采用ArkTS语法,符合HarmonyOS Next开发规范。实际使用时需根据具体业务场景调整回调逻辑和阈值参数。

回到顶部