在本篇博客中,我们将学习如何使用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/s2)。这意味着如果手机静止,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
将在以下情况下检测到摇晃:
SHAKE_COUNT
)SHAKE_TIMEOUT
)FORCE_THRESHOLD
)如果满足所有这些条件,我们将调用callback
并在再次触发事件之前等待1秒(SHAKE_THROTTLE
),以避免在长时间摇晃期间多次触发事件。
有趣的是,我们甚至不关心加速度向量方向的变化。这使得该算法略有不准确。如果您还记得上一节中的说明 - 如果手机正在下落,加速度向量将为0,我们的检查将检测为摇晃。但是我发现,在正常使用中,很难长时间持续地沿一个方向对手机施加加速度。您需要改变方向 - 这实际上就是摇晃。因此,对于实际使用来说,它已经足够好了(除非您在太空中👨🚀)。
剩下的唯一事情就是实例化一个ShakeDetector
并在加速度计更新时通知它。
const shakeDetector = new ShakeDetector(() => {
alert("Shake detected!!!")
});
startAccelerometerUpdates(
(data) => shakeDetector.onSensorData(data),
{ sensorDelay: "ui" }
);
您可以在nativescript-accelerometer
仓库中查看完整的演示。