スマホを振った時に何か処理させたいときですが、OnShake のような便利なイベントというのはありません。
残念ながら、振られたのか、ただの移動なのかはセンサーだけでは判断はできないのです。
「Android shake 検出」などのキーワードで、検索すると皆さんいろいろなロジックで検知しています。
( 基本的に、加速度センサーを使って検知します )
Delphi で作ったアプリで実装してみました。
加速度センサーのコンポーネント TMotionSensor と TTimer を使って、振り幅と、速度から、ざっくりとしたアルゴリズムで検知しています。
ざっくりとしたアルゴリズム
一定時間内(0.3秒)で、振り幅が ±1 以上であればカウントを行い、カウントが 3 以上になったらシェイクとみなしています。
シェイクの方向は X, Y, Z それぞれありますので、
( 基点の X + Y + Z ) - ( 時間内終点の X + Y + Z )
の値を振り幅としています。
設計画面
MotionSensor の Active を True にしておくのを忘れずに
サンプルコード
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
FMX.Controls.Presentation, System.Sensors, System.Sensors.Components;
type
TForm1 = class(TForm)
ToolBar1: TToolBar;
Switch1: TSwitch;
Label1: TLabel;
Timer1: TTimer;
MotionSensor1: TMotionSensor;
procedure Timer1Timer(Sender: TObject);
procedure Switch1Switch(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ private 宣言 }
public
keepPoint: Double; //位置保存
shakeCount: Integer; //振りカウント
{ public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.FormCreate(Sender: TObject);
begin
// 初期化
keepPoint := 0;
shakeCount := 0;
Label1.Text := ' ';
end;
procedure TForm1.Switch1Switch(Sender: TObject);
begin
//スイッチが ONになったらカウントの初期化と基本ざっくり位置を保存する
if Switch1.IsChecked then begin
shakeCount := 0;
Label1.Text := ' ';
keepPoint := MotionSensor1.Sensor.AccelerationX
+ MotionSensor1.Sensor.AccelerationY
+ MotionSensor1.Sensor.AccelerationZ;
end;
//Timerの起動を制御
Timer1.Enabled := Switch1.IsChecked;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
mPoint: Double; //作業用
begin
// 振りカウントが 3以上になったらシェイクとみなす
if shakeCount > 3 then begin
Label1.Text := 'しぇいく';
shakeCount := 0;
Switch1.IsChecked := False;
exit;
end;
// 現在位置ざっくり
mPoint := MotionSensor1.Sensor.AccelerationX
+ MotionSensor1.Sensor.AccelerationY
+ MotionSensor1.Sensor.AccelerationZ;
if ((keepPoint - mPoint) > 1) or ((keepPoint - mPoint) < -1) then begin
// 振りカウント +1
shakeCount := shakeCount + 1;
end;
// 現在ざっくり位置保存
keepPoint := mPoint;
end;
end.