タグ : multitouch

ドラッグした場合のステージ領域外検知の処理について

air for androidでドラッグを行う場合、なにも考えずに書くと下のようになる。

package
{
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.ui.Multitouch;
	import flash.ui.MultitouchInputMode;
	import flash.events.TouchEvent;

	public class Main extends Sprite
	{
		var mc:MovieClip;

		public function Main()
		{
			Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;

			mc = new MovieClip();
			mc.graphics.beginFill(0x000000);
			mc.graphics.drawCircle(100, 100, 100);
			mc.graphics.endFill();
			addChild(mc);

			mc.addEventListener(TouchEvent.TOUCH_BEGIN, touchBegin);
		}
		private function touchBegin(e:TouchEvent):void {
			trace("touchbegin");
			mc.startTouchDrag(e.touchPointID);
			mc.addEventListener(TouchEvent.TOUCH_END, touchEnd);
		}
		private function touchEnd(e:TouchEvent):void {
			trace("touchend");
			mc.stopTouchDrag(e.touchPointID);
			mc.removeEventListener(TouchEvent.TOUCH_END, touchEnd);
		}
	}
}

上記のように書くと、stage領域外に指が移動してしまった場合にTOUCH_ENDが発生しない。
これに加えてEvent.MOUSE_LEAVEも発生させることができますが、いまいち感度が良くなく(NexusOneでの確認のみ)マウス外に指がOUTする速度で発生したりしなかったりします。

これを回避するために以下のような記述でこれを回避することができます。
※この方法はStartTouchDragされるObjectが最前面にあるという条件付きです。

package  
{
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.ui.Multitouch;
	import flash.ui.MultitouchInputMode;
	import flash.events.TouchEvent;
	
	public class Main extends Sprite
	{
		private var mc:MovieClip;
		
		public function Main() 
		{
			Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
			
			mc = new MovieClip();
			mc.graphics.beginFill(0x000000);
			mc.graphics.drawCircle(100, 100, 100);
			mc.graphics.endFill();
			addChild(mc);
			
			mc.addEventListener(TouchEvent.TOUCH_BEGIN, touchBegin);
		}
		
		private function touchBegin(e:TouchEvent):void {
			trace("begin");
			
			//mcを最上面に移動する。mcの上にレイヤーがあると
			//レイヤーの下を通った際にtouchrolloutが発生してしまう。
			setChildIndex(mc, numChildren - 1);
			
			mc.startTouchDrag(e.touchPointID);
			mc.addEventListener(TouchEvent.TOUCH_ROLL_OUT, touchRollOut);
		}
		private function touchRollOut(e:TouchEvent):void {
			trace("touchRollout");
			
			mc.stopTouchDrag(e.touchPointID);
			mc.removeEventListener(TouchEvent.TOUCH_ROLL_OUT, touchRollOut);
		}
	}
}

Multitouch について

[この記事はベータ版(2010/09/23版)でしか確認をとれていません。正式リリース後に変更されている可能性もありますので参考程度にご覧ください。]

airforandroidでは、マルチタッチがサポートされています。

マルチタッチには2種類の入力方法があり、

  1. TouchEvent : マウスのようにクリックしたり従来のマウスイベントに相当するものを同時に複数扱う。
  2. GestureEvent : 複数の指を同時に動かせて、動き方によって入力内容を変えるもの。(ピンチズームなど)

があります。さらに詳しくはこちら>>

TouchEventについてはほとんどのデバイスで動きがサポートされていますが、GestureEventについてはos毎にサポートされているものやサポートされていない物が混在しているので注意が必要です。また、入力方法を事前に1と2のどちらを使うかを事前に宣言する必要があります。

1.TochEventの取得サンプル

package
{
	import flash.display.Sprite;
	import flash.text.TextField;

	import flash.ui.Multitouch;
	import flash.ui.MultitouchInputMode;
	import flash.events.TouchEvent;

	public class Main extends Sprite
	{
		private var txt:TextField;
		private var sp1:Sprite;
		private var sp2:Sprite;

		public function Main()
		{
			//デバッグ用txtfield
			txt = new TextField();
			txt.autoSize = "left";
			addChild(txt);

			sp1 = new Sprite();
			sp1.graphics.beginFill(0xFFCC00);
			sp1.graphics.drawCircle(0, 0, 80);
			sp1.y = 200;
			sp1.x = 100;
			addChild(sp1);

			sp2 = new Sprite();
			sp2.graphics.beginFill(0xFFFF00);
			sp2.graphics.drawCircle(0, 0, 80);
			sp2.y = 200;
			sp2.x = 300;
			addChild(sp2);

			//デバイスがマルチタッチをサポートしているか
			//どうか調べることができます。
			var isMultiTouchSupport:Boolean = Multitouch.supportsTouchEvents;

			//multiTouch宣言
			if (isMultiTouchSupport) {
				//TouchEventかGestureEventのどちらをりようするか宣言する(必須)
				Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;

				//最大認識できるタッチポイントの数(指何本まで認識できるか?)
				var maxTouchPoint:int = Multitouch.maxTouchPoints;
				txt.text = "このデバイスでは最大" + maxTouchPoint.toString() +"個のマルチタッチがサポートされています。";

				//リスナー登録
				sp1.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
				sp1.addEventListener(TouchEvent.TOUCH_END, onTouchEnd);
				sp1.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
				sp1.addEventListener(TouchEvent.TOUCH_TAP, onTouchTap);

				sp2.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
				sp2.addEventListener(TouchEvent.TOUCH_END, onTouchEnd);
				sp2.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
				sp2.addEventListener(TouchEvent.TOUCH_TAP, onTouchTap);

			}else {
				txt.text = "このデバイスではマルチタッチがサポートされていません。";
			}
		}

		private function onTouchBegin(e:TouchEvent):void {
			txt.text = "onTouchBegin : " + e.touchPointID + "\n";
			var temp:Sprite = e.target as Sprite;
			temp.startTouchDrag(e.touchPointID);
		}
		private function onTouchEnd(e:TouchEvent):void {
			txt.text = "onTouchEnd : " + e.touchPointID + "\n";
			var temp:Sprite = e.target as Sprite;
			temp.stopTouchDrag(e.touchPointID);
		}
		private function onTouchMove(e:TouchEvent):void {
			txt.appendText("onTouchMove : " + e.touchPointID+" \n");
		}
		private function onTouchTap(e:TouchEvent):void {
			txt.text = "onTouchTap : " + e.touchPointID + "\n";
		}
	}
}

2.GestureEvent

複数の指を同時に動かせて、動き方によって入力内容を変えるもの。
これはジェスチャーイベントと呼ばれています。ジェスチャーイベントにも種類が複数あり、デバイスによってサポートする範囲が異なります。
ちなみにNexusOneでサポートしているのは以下の5つでした。

  • gestureZoom
  • gesturePan
  • gestureRotate
  • gestureTwoFingerTap
  • gestureSwipe

どのようなジェスチャーが存在するか知りたい場合はこちらを参照ください。

package
{
	import flash.display.Sprite;
	import flash.text.TextField;

	import flash.ui.Multitouch;
	import flash.ui.MultitouchInputMode;

	public class Main extends Sprite
	{
		private var txt:TextField;
		private var sp1:Sprite;
		private var sp2:Sprite;

		public function Main()
		{
			//デバッグ用txtfield
			txt = new TextField();
			txt.autoSize = "left";
			addChild(txt);

			//デバイスがマルチタッチのジェスチャーイベントをサポートしているか
			//どうか調べることができます。
			var isMultiTouchSupport:Boolean = Multitouch.supportsGestureEvents;

			//multiTouch宣言
			if (isMultiTouchSupport) {
				//TouchEventかGestureEventのどちらをりようするか宣言する(必須)
				Multitouch.inputMode = MultitouchInputMode.GESTURE;

				//どのジェスチャーイベントをサポートしているかVectorで取り出せます。
				var supportGesture:Vector.<String> = Multitouch.supportedGestures;
				txt.text = "このデバイスでは下のイベントがサポートされています\n\n";
				for (var i:int = 0; i < supportGesture.length; i++) {
					txt.appendText(supportGesture[i]+"\n\n");
				}
			}else {
				txt.text = "このデバイスではマルチタッチ:ジェスチャーイベントがサポートされていません。";
			}
		}
	}
}

補足:TouchEventの動作テストサンプル

どのターゲットがイベントを出すかわかりやすくしてみたサンプルです。

apkファイルはこちら

package
{
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.text.TextField;
	import flash.ui.Multitouch;
	import flash.ui.MultitouchInputMode;
	import flash.events.TouchEvent;

	public class Main extends Sprite
	{
		public function Main()
		{
			Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;

			mc.addEventListener(TouchEvent.TOUCH_BEGIN, onTouch);
			mc.addEventListener(TouchEvent.TOUCH_END, onTouch);
			//mc.addEventListener(TouchEvent.TOUCH_MOVE, onTouch);
			mc.addEventListener(TouchEvent.TOUCH_OUT, onTouch);
			mc.addEventListener(TouchEvent.TOUCH_OVER, onTouch);
			mc.addEventListener(TouchEvent.TOUCH_ROLL_OUT, onTouch);
			mc.addEventListener(TouchEvent.TOUCH_ROLL_OVER, onTouch);
			mc.addEventListener(TouchEvent.TOUCH_TAP, onTouch);

			txt.addEventListener(TouchEvent.TOUCH_TAP,
						function (e:TouchEvent) {
							txt.text = "";
						}
			 );
		}
		private function onTouch(e:TouchEvent):void {
			txt.appendText(e.target.name+" : "+e.type + "\n");
		}
	}
}

備考:Multitouchの性能比較について
http://juggly.cn/archives/10845.html