Multitouch

One of the navigation methods unique to mobile devices is the ability to interact with an application via gestures on the device’s touchscreen. Multitouch is defined as the ability to simultaneously register three or more touch points on the device. Within Adobe AIR 2.6, there are two event classes used to listen for multitouch events.

GestureEvent

The GestureEvent class is used to listen for a two-finger tap on the device. The event used to listen for this action is GESTURE_TWO_FINGER_TAP. This event will return the registration points for the x and y coordinates when a two-finger tap occurs for both stage positioning as well as object positioning.

Let’s review the code below. Within applicationComplete of the application, an event handler function is called, which first sets the Multitouch.inputMode to MultitouchInputMode.GESTURE. Next, it checks to see if the device supports multitouch by reading the static property of the Multitouch class. If this property returns as true, an event listener is added to the stage to listen for GestureEvent.GESTURE_TWO_FINGER_TAP events. When this event occurs, the onGestureTwoFinderTap method is called., which will capture the localX and localY coordinates as well as the stageX and stageY coordinates. If you two-finger-tap on an empty portion of the stage, these values will be identical. If you two-finger-tap on an object on the stage, the localX and localY coordinates will be the values within the object, and the stageX and stageY will be relative to the stage itself. See Figure 4-9 for an example of a two-finger tap on the stage and Figure 4-10 for a two-finger tap on the Android image:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               applicationComplete="application1_applicationCompleteHandler(event)">
    <fx:Script>
          <![CDATA[
               import mx.events.FlexEvent;

               protectedfunction application1_applicationCompleteHandler
                   (event:FlexEvent):void {
                     Multitouch.inputMode = MultitouchInputMode.GESTURE;
                     if(Multitouch.supportsGestureEvents){
                          stage.addEventListener(GestureEvent.GESTURE_TWO_FINGER_TAP, 
                              onGestureTwoFingerTap);
                     } else {
                          status.text="gestures not supported";
                     }

               }
               privatefunction onGestureTwoFingerTap(event:GestureEvent):void {
                     info.text = "event = " + event.type + "\n" +
                          "localX = " + event.localX + "\n" +
                          "localX = " + event.localY + "\n" +
                          "stageX = " + event.stageX + "\n" +
                          "stageY = " + event.stageY;
               }

          ]]>
    </fx:Script>
    <fx:Declarations>
          <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
    <s:Label id="status" text="Do a 2 finger tap both on and off the object"
                top="10" width="100%" textAlign="center"/>
    <s:TextArea id="info" width="100%" top="40" editable="false"/>
    <s:Image width="384" height="384" bottom="10" horizontalCenter="0"
               source="@Embed('android_icon.png')"/>
</s:Application>
A two-finger tap on the stage

Figure 4-9. A two-finger tap on the stage

A two-finger tap on an image object

Figure 4-10. A two-finger tap on an image object

TransformGesture

There are multiple transform gesture events available within AIR 2.6. Each will capture a unique multitouch event. The example below demonstrates how to listen for GESTURE_PAN, GESTURE_ROTATE, GESTURE_SWIPE, and GESTURE_ZOOM events.

Let’s review the code below. Within applicationComplete of the application, an event handler function is called, which first sets the Multitouch.inputMode to MultitouchInputMode.GESTURE. Next, it checks to see if the device supports multitouch by reading the static property of the Multitouch class. If this property returns as true, event listeners are added to the stage to listen for the TransformGestureEvent.GESTURE_PAN, TransformGestureEvent.GESTURE_ROTATE, TransformGestureEvent.GESTURE_SWIPE, and TransformGestureEvent.GESTURE_ZOOM events.

When a user grabs an object with two fingers and drags it, the TransformGestureEvent.GESTURE_PAN event is triggered and the onGesturePan method is called. Within the onGesturePan method, the offsetX and offsetY values of this event are written to the text property of the TextArea component. Adding the event’s offsetX and offsetY values sets the object’s x and y to move the object across the stage. The results can be seen in Figure 4-11.

The GESTURE_PAN event

Figure 4-11. The GESTURE_PAN event

When a user grabs an object with two fingers and rotates it, the TransformGestureEvent.GESTURE_ROTATE event is triggered and the onGestureRotate method is called. Within the onGestureRotate method, the rotation value of this event is written to the text property of the TextArea component. To allow the object to rotate around its center, the object’s transformAround method is called and the event’s rotation value is added to the object’s rotationZ value. The results can be seen in Figure 4-12.

The GESTURE_ROTATE event

Figure 4-12. The GESTURE_ROTATE event

When a user swipes across an object with one finger in any direction, the TransformGestureEvent.GESTURE_SWIPE event is triggered and the onGestureSwipe method is called. Within the onGestureSwipe method, the values of the event’s offsetX and offsetY are evaluated to determine the direction in which the user swiped across the object. This direction is then written to the text property of the TextArea component. The results can be seen in Figure 4-13.

The GESTURE_SWIPE event

Figure 4-13. The GESTURE_SWIPE event

When a user performs a “pinch and zoom” action with two fingers on an object, the TransformGestureEvent.GESTURE_ZOOM event is triggered and the onGestureZoom method is called. Within the onGestureZoom method, the values of the event’s scaleX and scaleY are written to the text property of the TextArea component. The scaleX value is then used as a multiplier on the object’s scaleX and scaleY property to increase or decrease the size of the object as the user pinches or expands two fingers on the object. The results can be seen in Figure 4-14:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               applicationComplete="application1_applicationCompleteHandler(event)">
    <fx:Script>
          <![CDATA[
               import mx.events.FlexEvent;

               protectedfunction application1_applicationCompleteHandler
                   (event:FlexEvent):void {
                     Multitouch.inputMode = MultitouchInputMode.GESTURE;
                     if(Multitouch.supportsGestureEvents){
                          image.addEventListener(TransformGestureEvent.GESTURE_PAN, 
                              onGesturePan);                                                    image.addEventListener(TransformGestureEvent.GESTURE_ROTATE, 
                              onGestureRotate);
                          image.addEventListener(TransformGestureEvent.GESTURE_SWIPE, 
                              onGestureSwipe);
                          image.addEventListener(TransformGestureEvent.GESTURE_ZOOM, 
                              onGestureZoom);
                     } else {
                          status.text="gestures not supported";
                     }
               }

               privatefunction onGesturePan(event:TransformGestureEvent):void{
                     info.text = "event = " + event.type + "\n" +
                     "offsetX = " + event.offsetX + "\n" +
                     "offsetY = " + event.offsetY;
                     image.x += event.offsetX;
                     image.y += event.offsetY;
               }

               privatefunction onGestureRotate( event : 
                   TransformGestureEvent ) : void {
                     info.text = "event = " + event.type + "\n" +
                     "rotation = " + event.rotation;
                     image.transformAround(new Vector3D(image.width/2, 
                                                        image.height/2, 0),
                                                    null,
                                                    new Vector3D(0,0,image.rotationZ 
                                                         + event.rotation));
               }

               privatefunction onGestureSwipe( event : 
                   TransformGestureEvent ) : void {
                     var direction:String = "";
                     if(event.offsetX == 1) direction = "right";
                     if(event.offsetX == −1) direction = "left";
                     if(event.offsetY == 1) direction = "down";
                     if(event.offsetY == −1) direction = "up";
                     info.text = "event = " + event.type + "\n" +
                     "direction = " + direction;
               }

               privatefunction onGestureZoom( event : 
                   TransformGestureEvent ) : void {
                     info.text = "event = " + event.type + "\n" +
                     "scaleX = " + event.scaleX + "\n" +
                     "scaleY = " + event.scaleY;
                     image.scaleX = image.scaleY *= event.scaleX;
               }

               protectedfunction button1_clickHandler(event:MouseEvent):void
               {
                     image.rotation = 0;
                     image.scaleX = 1;
                     image.scaleY = 1;                     image.x = 40;
                     image.y = 260;
                     info.text = "";
               }

          ]]>
    </fx:Script>
    <fx:Declarations>
          <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
    <s:Label id="status" text="Transform Gestures" top="10" width="100%" 
        textAlign="center"/>
    <s:HGroup width="100%" top="40" left="5" right="5">
          <s:TextArea id="info" editable="false" width="100%" height="200"/>
          <s:Button label="Reset" click="button1_clickHandler(event)"/>
    </s:HGroup>
    <s:Image id="image" x="40" y="260" width="400" height="400"
                source="@Embed('android_icon.png')"/>
</s:Application>
The GESTURE_ZOOM event

Figure 4-14. The GESTURE_ZOOM event

Get Developing Android Applications with Flex 4.5 now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.