Tutorial: Multitouch Twitter Application
Introduction
Learn how to use an open source twitter API and the Touch Drag, Gesture Rotate and Gesture Scale events to create a multitouch twitter application. In this tutorial, we’ll find and manipulate the tweets posted by a defined username. This tutorial requires Adobe Flash CS4 and GestureWorks (download a free trial).
Creating Your Document Class
The document class also known as the “Application” class is the root object class for your application. The primary purpose of the document class is to extend the main timeline; it does this in the form of a custom MovieClip. This means that all other objects in your application are placed within it.
To set the document class for your application, open mainApp.fla. Then, in the main menu, go to File > Publish Settings. In the Flash tab, select the Script “settings” button. Then, in the “Advanced Actionscript 3 Settings” window, set the “Document Class” to “Main“. Press the “OK” button and apply the changes to publishing settings.
In the main menu, go to: File > New. Then, in the “New Document” window, select “Actionscript File” and press the “OK” button. Save the file as “Main.as” and make sure it is saved in the same folder as your application file.
In the first line of your ActionScript file, add the following code to open a new package structure:
1 | package { |
This defines the beginning of the root package which in turn defines the code used in your root class “Main”. This tells Flash what script to include when extending “Main”.
Importing Flash Libraries
The first thing we are going to do next is import the Flash display package into the package of our root class. Essentially this allows Flash to correctly reference and retrieve all the object resources that may be needed to display objects on the stage. In this case, we will only need the Sprite class as we will be using Sprites to contain other display objects.
2 | import Flash.display.Sprite; |
In this example, we are going to use a “textField” object to display text. To do this, we need to import the class libraries that handle text display and formatting.
3 | import Flash.text.*; |
Importing GestureWorks Libraries
Importing the “Application” package instantiates libraries and builds a framework of control structures for managing multitouch events and methods for object tracking within Flash. To edit these settings, open “How to Customize Application.xml”
4 | import id.core.Application; |
A display level class must be set up to be used for stage objects. To do this, we import the TouchSprite class libraries. TouchSprite builds multitouch onto the Sprite class. This means that TouchSprite inherits all the properties of Sprite and adds new event targeting features that act systematically to determine multitouch event ownership at the object level.
5 | import id.core.TouchSprite; |
Since we are going to be using touch events and gesture events, we’ll need to import these classes into our file.
6 | import gl.events.TouchEvent |
As with importing other packages, importing the TouchEvent and GestureEvent packages provides a reference to all available touch and gesture analysis modules via their class names.
7 | import gl.events.GestureEvent |
Importing Twitter Libraries
Our application will connect to the twitter website and retrieve information associated with a specific twitter feed. To do this in Flash, we need to use the open source library called “twitterscript”. This library of custom classes and methods is a specialized AS3 API for twitter developed by Michael Galpin [ http://code.google.com/p/twitterscript/ ].
8 9 | import com.twitter.api.events.TwitterEvent; import com.twitter.api.Twitter; |
Creating Your App
In order to build our multitouch application, we are going to create what is essentially a custom class in Flash. We begin this process by extending the “Application” class & setting up our new class to automatically inherit a multitouch framework that will manage touch events behind the scenes.
11 | public class Main extends Application { |
Set the variable “twitterUser” to hold your chosen twitter user name. This will be used to search twitter and find the twitter feed and associated tweets posted by the defined username.
12 | private var twitterUser:String = "gestureworks"; |
Create a twitter object to manage twitter queries between Flash and the twitter website.
13 | private var _twitter:Twitter; |
As in most cases, the document class should be defined as public so that it can be called (and instances created) from outside the package. In our document class, the first thing we are going to do is create a new instance of the twitter object then, using the “loadUserTimeline” method (made available by the imported “twitterscript” library), connect to the twitter website and download the feed associated with our specified twitter username. We then attach a TwitterEvent listener that calls the custom function “twitterResults” when the twitter stream has been successfully retrieved from the server.
15 16 17 18 19 | public function Main() { _twitter = new Twitter(); _twitter.loadUserTimeline(twitterUser); _twitter.addEventListener(TwitterEvent.ON_USER_TIMELINE_RESULT, twitterResults); } |
Next we are going to define the function “twitterResults”. This function will be designed to construct an interactive graphical representation of each tweet from the feed. To do this we will draw a simple rounded rectangle shape, create a dynamic text field within that shape, then populate the text field with data from a tweet. The individual objects will then be randomly placed on stage and given common multitouch and gesture interactivity.
21 | private function twitterResults(event:TwitterEvent):void { |
In this application, displayed text will be rotatable. In order for text to be displayed properly in Flash when at an angle, the font used to draw the text on stage must be embedded. To embed text in Flash, see: http://www.adobe.com/devnet/flash/quickstart/embedding_fonts/#section1
22 23 | var embeddedFont:Font = new Arial(); var margin:int = 20; |
As is common when working with text fields in Flash, the most effective method for setting text attributes is to construct a textFormat object that contains all the formatting information. In this “textFormat” object we set the text size to 14 px, set the text color to dark grey “0×222222″, align the text to the left and set the font to the embedded font type.
25 26 27 28 29 | var textFormat:TextFormat = new TextFormat(); textFormat.size = 14; textFormat.color = 0x222222; textFormat.align = TextFormatAlign.LEFT; textFormat.font = embeddedFont.fontName; |
Tweets by definition can be no longer than 140 characters so the required field to display this text is relatively small and has a maximum size. The typical number of tweets in a twitter timeline is no more than 20 by default. This means we can confidently create an object on stage for each tweet without objects being over-sized or too numerous to create a practical user interface. Since we want to create an object for each twitter post, we can use a simple loop to count through the list of tweets in the twitter timeline. The value event.data.length gives the total number of recent tweets returned from the “ON_USER_TIMELINE_RESULT” event.
31 | for (var i:int=0; i<event.data.length; i++){ |
Create a touchsprite holder to house the graphics and generated text.
32 | var touchElement:TouchSprite = new TouchSprite(); |
Make sure that blob containment is enabled so that touch and gesture events are contained within the object on which they are detected.
33 | touchElement.blobContainerEnabled = true; |
Next create a text field object and embed the font. Then set the value of the text field to event.data[i].text. This sets the content to a specific tweet returned from the twitter timeline query event “ON_USER_TIMELINE_RESULT”.
35 36 37 38 39 40 41 42 43 44 | var twitterText:TextField = new TextField(); twitterText.embedFonts = true; twitterText.defaultTextFormat = textFormat; twitterText.antiAliasType = AntiAliasType.ADVANCED; twitterText.text = twitterUser+"\n-----------------\n"+event.data[i].text; twitterText.wordWrap = true; twitterText.autoSize = TextFieldAutoSize.CENTER; twitterText.width = 200; twitterText.x = margin/2; twitterText.y = margin/2; |
Create a sprite object, then draw a simple round rectangle with a white fill and twitter blue outline that is slightly bigger than the dynamic text field.
46 47 48 49 50 | var touchBackground:Sprite = new Sprite(); touchBackground.graphics.lineStyle(6,0x00CCFF,1); touchBackground.graphics.beginFill(0xFFFFFF,1); touchBackground.graphics.drawRoundRect(0,0,twitterText.width+margin,twitterText.height+margin,20,20); touchBackground.graphics.endFill(); |
The parent touchSprite is then positioned at a random location on stage. In this example the stage size is 900×600. The horizontal position of the TouchSprite is set between 0 and 900px, then the vertical value is set between 0 and 600px.
52 53 | touchElement.x = Math.random()*stage.stageWidth; touchElement.y = Math.random()*stage.stageHeight; |
The orientation of the touchsprite is also set to a random angle between 0 and 360 degrees. This method makes the tweets appear randomly positioned and oriented when they appear on stage, as if thrown.
54 | touchElement.rotation = Math.random()*360; |
Next we attach the TouchEvent listeners to the touchSprite() object so that it can be dragged around the stage area. The first listener calls the function “touchDownHandler” each time a TOUCH_DOWN event is detected and the second calls “touchUpHandler” when a TOUCH_UP event is detected.
56 57 | touchElement.addEventListener(TouchEvent.TOUCH_DOWN, touchDownHandler); touchElement.addEventListener(TouchEvent.TOUCH_UP, touchUpHandler); |
Attach a GESTURE_ROTATE event listener to your TouchSprite() object. This calls the function “gestureRotateHandler” each time a GESTURE_ROTATE event is detected on “touchElement”.
58 | touchElement.addEventListener(GestureEvent.GESTURE_ROTATE, gestureRotateHandler); |
Since we want to be able to change the scale of our image, we must listen for a “scale” or “pinch” gesture on the object and call a specific function that can handle scale changes when the scale event is triggered. To accomplish this, we simply add a “GESTURE_SCALE” listener to the “touchElement” TouchSprite. This listener will call the function “gestureScaleHandler” each time a “scale” gesture occurs on the container object.
59 | touchElement.addEventListener(GestureEvent.GESTURE_SCALE, gestureScaleHandler); |
Next, we nest the “twitterText” object inside the “touchBackground” sprite and then nest them both inside the “touchElement” TouchSprite() using the addChild() method. We then add the container “touchElement” to the stage so that it is added to the display list and all associated nested content is drawn on screen at runtime.
61 62 63 | touchBackground.addChild(twitterText); touchElement.addChild(touchBackground); addChild(touchElement); |
When TOUCH_DOWN is dispatched, we want our object to pop to the top of the pile and to begin dragging on stage. To do this, we enable startTouchDrag(), then reset the index of the object so that it is at the top of the display list. The startTouchDrag() method behaves in a similar way to the startDrag() method; however, this touch method works by updating the position of the object every time the touch point above it moves. Setting the “touch point ID” parameter to “-1″ effectively ensures that start drag does not respond to Adobe’s native single touch point ID and allows dragging to automatically occur with multiple touch points (when using transformations).
67 68 69 70 71 | private function touchDownHandler(event:TouchEvent):void { var obj:* = event.target; event.target.startTouchDrag(-1); setChildIndex(obj, numChildren-1); } |
The same logic is then applied to releasing the objects. When a TOUCH_UP event is triggered on one of the TouchSprite objects, the “stopTouchDrag()” method is called.
73 74 75 | private function touchUpHandler(event:TouchEvent):void { event.target.stopTouchDrag(-1); } |
Gesture events can be treated the same way as touch events. Both TouchSprite objects call the same function “gestuerRotateHandler()” each time a GESTURE_ROTATE event is dispatched. Every time a GESTURE_ROTATE event is dispatched from your TouchSprite, a value is returned which measures the calculated change in orientation (rotation) of the cluster of touch points on your touch object. This value is used to incrementally change the angle of orientation of “container”, adding the change to the previous value each time the event is detected.
77 78 79 | private function gestureRotateHandler(event:GestureEvent) { event.target.rotation += event.value; } |
In addition to rotate, each time the “scale” gesture is detected on the “touchElement” object, a GESTURE_SCALE event is fired. This is detected by the gesture listener we placed on the container object and calls the function “gestureScaleHandler”. Each time this occurs, a value for the change in scale is taken from the event and used to incrementally change the scale value of the target.
81 82 83 84 | private function gestureScaleHandler(event:GestureEvent) { event.target.scaleX += event.value; event.target.scaleY += event.value; } |
In this example, the center of rotation and center of scale of the touch object is determined dynamically by the relative position of the points used in the gesture. This is done by modifying the display objects using matrix transformations that allow the user to change the center of rotation or scale while in the process of performing multiple concurrent gestures. The result is a smooth, physically accurate pivoting of touch sprites about the center of rotation which can be defined by a combination of gestures.
Summary
Our multitouch twitter application connects to twitter and looks for the twitter timeline matching the “gestureworks” username. It then retrieves information on those posts, creates a list of TouchSprite objects —each containing a tweet from the timeline— then randomly places and orients them on the stage. Each one of the TouchSprite objects can be independently dragged, dropped, rotated and scaled by multiple users. With a few minor changes this application could be expanded to include basic physics effects and simple tweet management logic that can enable new tweets to be thrown onstage when they are posted. In this way you can create a fully functional multitouch multiuser tweet deck.
Complete Example Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | package { import Flash.display.Sprite; import Flash.text.*; import id.core.Application; import id.core.TouchSprite; import gl.events.TouchEvent; import gl.events.GestureEvent; import com.twitter.api.events.TwitterEvent; import com.twitter.api.Twitter; public class Main extends Application { private var twitterUser:String="gestureworks"; private var _twitter:Twitter; public function Main() { _twitter = new Twitter(); _twitter.loadUserTimeline(twitterUser); _twitter.addEventListener(TwitterEvent.ON_USER_TIMELINE_RESULT, twitterResults); } private function twitterResults(event:TwitterEvent):void { var embeddedFont:Font = new Arial(); var margin:int = 20; var textFormat:TextFormat = new TextFormat(); textFormat.size = 14; textFormat.color = 0x222222; textFormat.align = TextFormatAlign.LEFT; textFormat.font = embeddedFont.fontName; for (var i:int=0; i<event.data.length; i++) { var touchElement:TouchSprite = new TouchSprite(); touchElement.blobContainerEnabled=true; var twitterText:TextField = new TextField(); twitterText.embedFonts = true; twitterText.defaultTextFormat = textFormat; twitterText.antiAliasType = AntiAliasType.ADVANCED; twitterText.text = twitterUser+"\n-----------------\n"+event.data[i].text; twitterText.wordWrap = true; twitterText.autoSize = TextFieldAutoSize.CENTER; twitterText.width = 200; twitterText.x = margin/2; twitterText.y = margin/2; var touchBackground:Sprite = new Sprite(); touchBackground.graphics.lineStyle(6,0x00CCFF,1); touchBackground.graphics.beginFill(0xFFFFFF,1); touchBackground.graphics.drawRoundRect(0,0,twitterText.width+margin,twitterText.height+margin,20,20); touchBackground.graphics.endFill(); touchElement.x = Math.random()*stage.stageWidth; touchElement.y = Math.random()*stage.stageHeight; touchElement.rotation = Math.random()*360; touchElement.addEventListener(TouchEvent.TOUCH_DOWN, touchDownHandler); touchElement.addEventListener(TouchEvent.TOUCH_UP, touchUpHandler); touchElement.addEventListener(GestureEvent.GESTURE_ROTATE, gestureRotateHandler); touchElement.addEventListener(GestureEvent.GESTURE_SCALE, gestureScaleHandler); touchBackground.addChild(twitterText); touchElement.addChild(touchBackground); addChild(touchElement); } } private function touchDownHandler(event:TouchEvent):void { var obj:* = event.target; event.target.startTouchDrag(-1); setChildIndex(obj, numChildren-1); } private function touchUpHandler(event:TouchEvent):void { event.target.stopTouchDrag(-1); } private function gestureRotateHandler(event:GestureEvent) { event.target.rotation += event.value; } private function gestureScaleHandler(event:GestureEvent) { event.target.scaleX += event.value; event.target.scaleY += event.value; } } } |
Testing Your Application
There are various ways to test your multitouch application. If you have a multitouch imput device, events can be directly streamed to your Flash application via TUIO. If you do not have a device that can output multitouch events, you can use the built-in simulator in GestureWorks. To test your app in the main menu, go to Control > Test Movie or press “Ctrl + Enter” on the keyboard. Alternatively, you can publish your application as a self-contained executable by following these steps:
- In your open Flash application “myApp.fla“, go to File > Publish Settings.
- Then in the Formats tab, select “Windows Projector” or “Macintosh Projector,” then press the “Publish” button.
- The application will be published to your appfolder; from there, you can simply double click on myApp.exe (Windows) or myApp.app (Mac) and run your multitouch application.
NOTE - To build and test these tutorials on a computer without a touchscreen display, pressing “Shift” or “Control” while clicking on an object with the mouse will create additional touch points within the simulator. To remove touch points, simply click them.
Related Gestures
Other Tutorials In The "Getting Started With Gestures" Series
These tutorials cover the basics of how to integrate touch and gesture events into your Flash applications:
- Flash
- How to create an application using Touch Tap
- How to create an application using Touch Drag
- How to create an application using the Rotate Gesture
- How to create an application Using the Zoom Gesture
- How to creat e an application using the Flick Gesture
- How to create a multi-user application using Drag, Rotate and Scale
- How to create a Google Maps application with Move, Double Tap, Rotate, Scale and Tilt
- How to create a multitouch Twitter application
- How to create a multitouch 3D application
- How to create a multitouch real-time Sound Manipulation application
- Flex
- How to create a Flex application using multitouch Scroll
- How to create a multitouch SVG Viewer in Flex




