タッチシーケンスは、タッチデバイスに触れてから離れるまでのタッチポイントの一連の動きのことです。タッチシーケンスを把握すると、自前のジェスチャも実装できるようになります。
タッチシーケンスは 1 つの touchBegin イベントと、必要に応じて 1 つ以上の touchMove イベント、それから 1 つの touchEnd イベントからなります。
タッチシーケンス: touchBegin (1) → touchMove (0 以上) → touchEnd (1)
touchBegin から touchEnd までの一連のイベントを順番に並べることで、タッチポイントの軌跡が再現等ができるようになります。
タッチポイントの識別
ところで、マルチタッチをサポートするデバイスの場合は、複数のタッチシーケンスが並行して発生する可能性があります。例えば、タッチパネル上で親指と人差し指を同時に動かしている間は、両方の指から touchMove イベントが発生し続けます。
そのような場合には、それぞれのイベントがどちらのタッチポイントに属するものかを区別しないと、正しいシーケンスを把握することができません。そのため、TouchEvent を処理する際は、TouchEvent.touchPointID 属性を使って、イベントの元となったタッチポイントを判断するという処理が必要になってきます。
下のコードは、最初の touchBegin イベントで touchPointID を記録しておくことで、他の touchPointID を持つイベントは無視する、というイベントハンドラのサンプルです。オブジェクトを指でドラッグしたいときなどは、指 1 本だけでの操作なので、このようなアプローチが有効かもしれません。
// 追跡中のタッチポイントのID var currentID:int = 0; function onTouchBegin(e:TouchEvent) { if(currentID != 0) { // 既にシーケンスが開始されているためそのまま終了 return; } // タッチポイントのIDを保存 currentID = e.touchPointID; // その他必要な処理を行う } function onTouchMove(e:TouchEvent) { if(e.touchPointID != currentID) { // 別のシーケンスのイベントは無視する return; } // オブジェクトの移動など、必要な処理を行う } function onTouchEnd(e:TouchEvent) { if(e.touchPointID != currentID) { // 別のシーケンスのイベントは無視する return; } // 変数を初期値に戻す currentID = 0; // その他必要な処理を行う }
もし、ズームや回転のジェスチャーを TouchEvent で実装したい場合には 2 つ目のタッチポイントまで扱えるように変えることになります。あとは、タッチシーケンスの軌跡を正確に判断するロジックを揃えることさえできれば、ジェスチャーの実装はそれほど難しくないかも?ですね。
イベントハンドラの登録
さて、話を上のサンプルに戻して、イベントハンドラを追加するコードも足してみます。
操作開始の合図となる touchBegin イベントのハンドラは、操作する対象となるオブジェクトに追加する、で良さそうです。ですが、touchMove や touchEnd イベントは、タッチポイントが最初に触れたオブジェクトの外側に移動してから離れた場合のことを考えると、そのオブジェクトの外で発生するイベントも拾える必要がありそうです。そのため、touchMove と touchEnd のハンドラは stage に追加することにします。
オブジェクトをドラッグする場合は常にタッチポイントの下にオブジェクトがありそうな気もしますが、ドラッグ可能な領域の外側にタッチポイントが移動することはあり得るので、やはり touchMove と touchEnd のハンドラは stage に追加しておいた方が安全そうです。
ということで、下はイベントシーケンスを使ってオブジェクトをドラッグするサンプルです。touchBegin のイベントハンドラで touchMove と touchEnd のイベントハンドラを追加し、touchEnd のイベントハンドラで touchMove と touchEnd のイベントハンドラを削除しています。
Multitouch.inputMode=MultitouchInputMode.TOUCH_POINT; // 追跡中のタッチポイントのID var currentID:int = 0; // ドラッグするオブジェクト var mySprite:Sprite = new Sprite(); mySprite.graphics.beginFill(0xFFCC00); mySprite.graphics.drawCircle(50, 50, 40); addChild(mySprite); mySprite.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin); function onTouchBegin(e:TouchEvent) { if(currentID != 0) { // 既にシーケンスが開始されているためそのまま終了 return; } // タッチポイントのIDを保存 currentID = e.touchPointID; // stageにイベントハンドラを登録 stage.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove); stage.addEventListener(TouchEvent.TOUCH_END, onTouchEnd); // その他必要な処理を行う } function onTouchMove(e:TouchEvent) { if(e.touchPointID != currentID) { // 別のシーケンスのイベントは無視する return; } mySprite.x = e.stageX; mySprite.y = e.stageY; } function onTouchEnd(e:TouchEvent) { if(e.touchPointID != currentID) { // 別のシーケンスのイベントは無視する return; } // 変数を初期値に戻す currentID = 0; // stageからイベントハンドラを削除 stage.removeEventListener(TouchEvent.TOUCH_MOVE, onTouchMove); stage.removeEventListener(TouchEvent.TOUCH_END, onTouchEnd); // その他必要な処理を行う }
コメントする