Banner


Page: 1 

  06-02-11 1:56am Handling iPhone Stage Orientation




Posts: 0
My last tutorial focused on saving images to the devices camera roll. It was really an easy process made possible through the ActionScript class CameraRoll.
----------------------------------------------------------
What you will learn...
• How to handle screen orientation changes on your iPhone
• How to listen for and handle gesture pan events

What you should know...
• ActionScript 3.0 basics (variables, conditionals, loops, events, etc.)
• How to get an application on your iPhone

What you should have...
• A iOS developer account to test on your iOS device
• Flash CS5
----------------------------------------------------------
In this tutorial we’re going to continue building onto the project from last time but adding a couple new concepts in. First off I’m going to show you how to handle screen orientation changes on your iPhone. Second, I’m going to show you how to listen for, and handle pan gesture events. If you haven’t done so already please read my last article on Saving Images to the Camera roll.

The ActionScript
If you’re continuing from the last article you should have the code already written and working. If you haven’t followed along so far please read the last issue of Flash and Flex Developer’s Magazine to catch up.
We’re going to jump right in to explaining the new code. We’re going to start off in the constructor. In the constructor I’ve setup MultitouchInputMode.GESTURE[/u] as the value for the [u]inputMode[/u] property of the [u]Multitouch[/u] class. So add this line in the constructor. [u]Multitouch.inputMode = MultitouchInputMode.GESTURE
This effectively sets up the device to handle predefined gestures like zoom (pinch), rotate and two-finger tap. With that setup, I’ll focus on the screen orientation aspect of this project. The first thing you’ll need to do is go into your iPhone OS Settings in the Properties panel (Figure 1). In there you’ll find a check box for Auto Orientation (Figure 2). Check the box, click OK (Figure 3), and test your application. Once the application is running, click the device menu located near the top of the application window, and click rotate left (Figure 4). Once the device rotates you’ll notice that the content gets place in the centered and scaled down. That doesn’t look to appealing. The application took it upon itself to handle the repositioning and scaling of the content on its own. To prevent this from happening we need to approach this in steps:
1. Make sure that Flash doesn’t resize the application when the screen changes orientation.
2. Create specific methods for portrait and landscape orientations.
3. Listen to and handle orientation events.
Listing 1. Private Function
START CODE
private function portraitView ():void
{
save_btn.y = 436;
save_btn.width = stage.stageWidth – 26;
status_txt.y = 395;
status_txt.x = 13;
_loader.y = 0;
_loader.scaleX = _loader.scaleY =
1;
_loader.removeEventListener (TransformGe
stureEvent.GESTURE_PAN, doPan);
}
private function landScapeView ():void
{
save_btn.y = 276;
save_btn.width = stage.stageWidth – 26;
status_txt.y = 235;
status_txt.x = (stage.stageWidth –
status_txt.width) / 2;
_loader.y = 0;
_loader.scaleX = _loader.scaleY
+= (stage.stageWidth – _
loader.width) / _loader.width;
_loader.addEventListener (TransformGe
stureEvent.GESTURE_PAN, doPan,
false, 0, true);
}
END CODE

Based on the first step we need to prevent the resizing of the application. If you’ve ever worked with EVENT.RESIZE you know that you need to set the scale mode of the stage to not scale and set the align property of the stage to top left. Same rules apply here. Add these two lines of ActionScript to the constructor.

[u]stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;[/u]

This prevents the stage from resizing and aligns the content to the top left corner of the device. Go ahead and run your application now. Notice when you rotate the device that the content is fixed to the top left corner and remains at the same size. But there’s a problem. Now half of your content is cropped off (Figure 5). To fix the problem we’ll need actual listen for orientation changes on the device, then resize and reposition the content accordingly. Add the following line under the other stage properties.

stage.addEventListener (StageOrientationEvent.ORIENTATION_CHANGE, stageChange, false, 0, true);

Stage orientation events are dispatched when the orientation of the devices changes, either from portrait to landscape or landscape to portrait. When this happens and the orientation has changed we will execute a method called stageChange. Add the following method to your code.

[u]private function stageChange (e:StageOrientationEvent):
void
{
switch (e.afterOrientation)
{
case StageOrientation.DEFAULT:
case StageOrientation.UPSIDE_DOWN:[/u]

BEGIN CODE
Listing 2a. The Document Class
package
{
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.ErrorEvent;
import flash.events.MouseEvent;
import flash.media.CameraRoll;
import flash.net.URLRequest;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.events.StageOrientationEvent;
import flash.display.StageOrientation;
import flash.ui.MultitouchInputMode;
import flash.events.TransformGestureEvent;
import flash.ui.Multitouch;
public class DocumentClass extends Sprite
{
private var _loader:Loader;
private var _cameraRoll:CameraRoll;
public function DocumentClass ()
{
save_btn.enabled = false;
Multitouch.inputMode = MultitouchInputMode.GESTURE;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.addEventListener (StageOrientationEvent.ORIENTATION_CHANGE,
stageChange, false, 0, true);
_loader = new Loader ();
_loader.contentLoaderInfo.addEventListener (Event.COMPLETE, imageComplete,
false, 0, true);
_loader.load (new URLRequest ("http://www.desktopwallpaperspace.com/pics/pic-
15092-320x480.jpg"<img src=" title=";)">);
}
private function imageComplete (e:Event):void
{
_cameraRoll = new CameraRoll ();
save_btn.enabled = true;
save_btn.addEventListener (MouseEvent.CLICK, saveImage, false, 0, true);
this.addChildAt (_loader, 0);
_loader.contentLoaderInfo.removeEventListener (Event.COMPLETE, imageComplete);
END CODE

BEGIN CODE
Listing 2b. The Document Class
}
private function saveImage (e:MouseEvent):void
{
status_txt.text = "";
if (CameraRoll.supportsAddBitmapData)
{
save_btn.visible = status_txt.visible = false;
var bmd:BitmapData = new BitmapData (stage.stageWidth,
stage.stageHeight);
bmd.draw (stage);
save_btn.visible = status_txt.visible = true;
save_btn.enabled = false;
save_btn.removeEventListener (MouseEvent.CLICK, saveImage);
_cameraRoll.addEventListener (ErrorEvent.ERROR, onImageError, false, 0, true);
_cameraRoll.addEventListener (Event.COMPLETE, onImageSave, false,
0, true);
_cameraRoll.addBitmapData (bmd);
}
else
{
status_txt.text = "Sorry your device doesn't support saving
images to the camera roll";
}
}
private function onImageError (e:ErrorEvent):void
{
status_txt.text = "There was a problem saving your image to the camera roll";
}
private function onImageSave (e:Event):void
{
status_txt.text = "The image was successfully saved to the camera roll";
save_btn.enabled = true;
save_btn.addEventListener (MouseEvent.CLICK, saveImage, false, 0, true);
_cameraRoll.removeEventListener (ErrorEvent.ERROR, onImageError);
_cameraRoll.removeEventListener (Event.COMPLETE, onImageSave);
}
private function stageChange (e:StageOrientationEvent):void
{
switch (e.afterOrientation)
END CODE

BEGIN CODE
Listing 2a. The Document Class
{
case StageOrientation.DEFAULT:
case StageOrientation.UPSIDE_DOWN:
portraitView ();
break;
case StageOrientation.ROTATED_LEFT:
case StageOrientation.ROTATED_RIGHT:
landScapeView ();
break;
default:
break;
}
}
private function portraitView ():void
{
save_btn.y = 436;
save_btn.width = stage.stageWidth – 26;
status_txt.y = 395;
status_txt.x = 13;
_loader.y = 0;
_loader.scaleX = _loader.scaleY = 1;
_loader.removeEventListener (TransformGestureEvent.GESTURE_PAN, doPan);
}
private function landScapeView ():void
{
save_btn.y = 276;
save_btn.width = stage.stageWidth – 26;
status_txt.y = 235;
status_txt.x = (stage.stageWidth – status_txt.width) / 2;
_loader.y = 0;
_loader.scaleX = _loader.scaleY += (stage.stageWidth – _loader.width) / _loader.width;
_loader.addEventListener (TransformGestureEvent.GESTURE_PAN, doPan, false, 0,
true);
}
private function doPan (e:TransformGestureEvent):void
{
_loader.y += e.offsetY;
}
}
}
END CODE

[u]portraitView ();
break;
case StageOrientation.ROTATED_LEFT:
case StageOrientation.ROTATED_RIGHT:
landScapeView ();
break;
default:
break;
}
}[/u]

In the stageChange method we execute a switch based on the value of e.afterOrientation.[/u] The afterOrientation property is available through the [u]StageOrientationEvent class and may output the following results:

StageOrientation.DEFAULT – The phone is in the upright position.
StageOrientation.ROTATED _ RIGHT – The phone has been rotated to the right.
StageOrientation. ROTATED _ LEFT – The phone has been rotated to the left.
StageOrientation.UPSIDE _ DOWN – The phone is upside down.

Inside the switch we setup cases based on those values. If StageOrientation.DEFAULT[/u] or [u]StageOrientation.UPSIDE _ DOWN[/u] are returned we call the [u]portraitView[/u] method. If the other two values are returned we will execute the [u]landScapeView[/u] method instead. Each of these methods sets up the look and feel for each orientation. Add the following two methods after the [u]stageChange method.
Each method repositions and scales the content to fit perfectly with in each orientation. What’s special about these two is the event listener that is added in landScapeView[/u] and removed in [u]portraitView[/u]. We add a [u]TransformGestureEvent[/u] listener to the [u]_loader. In landscape view you won’t be able to see the full image.
By pressing two fingers down on the image, we can now successfully move the image around on screen. When you place your two fingers down and begin to move, the doPan method will be exectured. Please add the following method to the end of your code.

BEGIN CODE
private function doPan (e:TransformGestureEvent):void
{
_loader.y += e.offsetY;
}
END CODE

I’ve limited the panning to only the y-axis. This prevents the user from moving the image on x-axis and locks them in on the y. I didn’t add any constraints to the scrolling on the y-axis but feel free to.

Testing
Go ahead and test your application in Flash. You should see your image load in with the button on top of it. Rotate your device and play with the newly added pan feature. If you encounter any problems make sure your code matches Listing 2.

Conclusion
That’s it. You’ve learned two new concepts on mobile development through Flash and ActionScript. These are two concepts to the many that were recently added to release of AIR 2.6. Which I plan on getting into on the next issue.

 

Page: 1 



Whos Online
Our members have posted 348 total posts and we have 36 members.
Our newest member is cyleewh.

There is currently 0 member(s) and 1 guest(s) online.

Theme Select: