# 在 NativeScript 中检测震动

·

在本博客中,我们将学习如何使用 nativescript-accelerometer 插件在 NativeScript 应用程序中检测“晃动”手势。

摇狗

获取加速度计数据
首先,我们将使用该 nativescript-accelerometer 插件开始监听加速度计数据:

import { startAccelerometerUpdates, AccelerometerData } from 'nativescript-accelerometer';
startAccelerometerUpdates(
  (data: AccelerometerData) => {
    console.log('x: ' + data.x + 'y: ' + data.y + 'z: ' + data.z);
  },
  { sensorDelay: 'ui' }
);

这样就 AccelerometerData 为我们提供了每个 x,y,z 轴的当前加速度计读数。因为我们通过 sensorDelay: "ui"了插件,所以大约每 60 毫秒就会读取一次,这似乎足以满足我们的目的。

电话轴

我们获得的值已归一化。的值 1 实际上等于地球的加速度(9.81 m / s 2)。这意味着如果电话静止不动,AccelerometerData 向量将指向地面,并且其长度($ \ sqrt {x ^ 2 + y ^ 2 + z ^ 2} $)相等 1。

注意:这也意味着,如果手机处于自由落体状态(或被抛向空中),则该矢量的长度将为零,因为它将处于失重状态。总结:电话不移动->矢量长度 1,电话掉落->矢量长度为零。对于加速度计的工作方式,这是一个有趣的(有点反常)的结果。

检测震动
现在,让我们实现抖动检测。

摇动手机意味着我们正在朝不同的方向施加力量。从牛顿第二定律我们知道$ \ vec {F} = m \ vec {a} $,这会导致加速度矢量发生变化。

我们将使用 ShakeDetector 实现。callback 当检测到抖动时,它接受一个被调用,并期望它 onSensorData(data)被来自加速度计的值调用。启动/停止加速度计的更新留给班级的使用者。

import { time } from "tns-core-modules/profiling";
import { AccelerometerData } from "nativescript-accelerometer";
const FORCE_THRESHOLD = 0.5;
const TIME_THRESHOLD = 100;
const SHAKE_TIMEOUT = 800;
const SHAKE_THROTTLE = 1000;
const SHAKE_COUNT = 3;
export class ShakeDetector {
  private lastTime = 0;
  private lastShake = 0;
  private lastForce = 0;
  private shakeCount = 0;
  private cb: Function;
  constructor(callback: () => void) {
    this.cb = zonedCallback(callback);
  }
  public onSensorData(data: AccelerometerData) {
    const now = time();
    if ((now - this.lastForce) > SHAKE_TIMEOUT) {
      this.shakeCount = 0;
    }
    const timeDelta = now - this.lastTime;
    if (timeDelta > TIME_THRESHOLD) {
      const forceVector = Math.abs(Math.sqrt(Math.pow(data.x, 2) + Math.pow(data.y, 2) + Math.pow(data.z, 2)) - 1);
      if (forceVector > FORCE_THRESHOLD) {
        this.shakeCount++;
        if ((this.shakeCount >= SHAKE_COUNT) && (now - this.lastShake > SHAKE_THROTTLE)) {
          this.lastShake = now;
          this.shakeCount = 0;
          this.cb();
        }
        this.lastForce = now;
      }
      this.lastTime = now;
    }
  }
}

ShakeDetector 如果出现以下情况,它将检测到晃动:

  • 记录 3 个读数(SHAKE_COUNT)
  • 相隔不到 800 毫秒(SHAKE_TIMEOUT)
  • 且加速度矢量长度与 1(我们从地球重力获得的恒定加速度)相差至少 0.5(FORCE_THRESHOLD)
    如果满足所有这些条件,我们将呼叫 callback 并等待 1 秒(SHAKE_THROTTLE),然后再次触发该事件,以避免在长时间摇晃时多次触发该事件。

有趣的是,我们甚至不关心加速度矢量方向的变化。这使得该算法有点不准确。如果您还记得上一节中的笔记-如果手机掉落,则加速度矢量将为 0,并且我们的检查将被检测为晃动。但是我发现,在正常使用情况下,很难长时间持续沿一个方向施加电话加速度。您将不得不更改方向-实际上是摇一摇。因此,对于实际使用而言,它已经足够了(除非您在太空中)。

全部放在一起
剩下要做的唯一事情就是实例化 a ShakeDetector 并在加速器更新时通知它:

const shakeDetector = new ShakeDetector(() => {
  alert('Shake detected!!!');
});
startAccelerometerUpdates(data => shakeDetector.onSensorData(data), { sensorDelay: 'ui' });

您可以在 nativescript-accelerometer 回购中查看完整的演示。