Flex Chart DataTip Renderer

Here is a quick post with some code to create custom DataTip renderers for Flex charts using Spark components and containers. Below is a screen shot of the custom DataTip and the source code to create it follows.

Main.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
					   xmlns:s="library://ns.adobe.com/flex/spark" 
					   xmlns:mx="library://ns.adobe.com/flex/mx" 
					   xmlns:charts="com.thanksmister.charts.*" 
					   width="480" height="340">
	
	<fx:Style source="assets/css/style.css"/>
	
	<fx:Script>
		<![CDATA[
			import mx.charts.CategoryAxis;
			
			private function categoryAxis_labelFunc(item:Object, prevValue:Object, axis:CategoryAxis, categoryItem:Object):String 
			{
				var datNum:Number = Date.parse(item);
				var tempDate:Date = new Date(datNum);
				
				return dateFormatter.format(tempDate).toUpperCase();
			}
		]]>
	</fx:Script>
	
	<fx:Declarations>
		<mx:DateFormatter id="dateFormatter" formatString="MMMM-DD-YYYY" />
	
		<s:XMLListCollection id="dp">
			<s:source>
				<fx:XMLList>
					<quote date="8/1/2007" open="40.29" close="39.58" />
					<quote date="8/2/2007" open="39.4" close="39.52" />
					<quote date="8/3/2007" open="39.47" close="38.75" />
					<quote date="8/6/2007" open="38.71" close="39.38" />
					<quote date="8/7/2007" open="39.08" close="39.42" />
					<quote date="8/8/2007" open="39.61" close="40.23" />
					<quote date="8/9/2007" open="39.9" close="40.75" />
					<quote date="8/10/2007" open="41.3" close="41.06" />
					<quote date="8/13/2007" open="41" close="40.83" />
					<quote date="8/14/2007" open="41.01" close="40.41" />
					<quote date="8/15/2007" open="40.22" close="40.18" />
					<quote date="8/16/2007" open="39.83" close="39.96" />
					<quote date="8/17/2007" open="40.18" close="40.32" />
					<quote date="8/20/2007" open="40.55" close="40.74" />
					<quote date="8/21/2007" open="40.41" close="40.13" />
					<quote date="8/22/2007" open="40.4" close="40.77" />
					<quote date="8/23/2007" open="40.82" close="40.6" />
					<quote date="8/24/2007" open="40.5" close="40.41" />
					<quote date="8/27/2007" open="40.38" close="40.81" />
				</fx:XMLList>
			</s:source>
		</s:XMLListCollection>

		<s:SolidColorStroke id="lineStroke" color="#CCCCCCC" alpha=".2" weight="1"/>
		
	</fx:Declarations>
	
	<s:VGroup width="100%" height="100%" paddingBottom="10" paddingTop="10" paddingLeft="10" paddingRight="10">
		
		<mx:LineChart id="lineChart"
					  showDataTips="true"
					  dataProvider="{dp}"
					  width="100%" gutterRight="10"
					  height="100%" 
					  dataTipRenderer="com.thanksmister.charts.DataTipSkin">
			
			<!-- vertical axis -->
			<mx:verticalAxis>
				<mx:LinearAxis baseAtZero="false" title="Price" />
			</mx:verticalAxis>
			
			<!-- horizontal axis -->
			<mx:horizontalAxis>
				<mx:CategoryAxis id="ca" categoryField="@date" title="Date" labelFunction="categoryAxis_labelFunc" />
			</mx:horizontalAxis>
			
			<!-- horizontal axis renderer -->
			<mx:horizontalAxisRenderers>
				<mx:AxisRenderer axis="{ca}" canDropLabels="true" />
			</mx:horizontalAxisRenderers>
			
			<!-- series -->
			<mx:series>
				<mx:LineSeries yField="@open" form="segment" displayName="Open" />
			</mx:series>
			
			<!-- series filters -->
			<mx:seriesFilters>
				<fx:Array/>
			</mx:seriesFilters>
			
			<!-- assign stroke to grid lines -->
			<mx:backgroundElements>
				<mx:GridLines gridDirection="both" horizontalChangeCount="2" verticalChangeCount="6">
					<mx:horizontalStroke>{lineStroke}</mx:horizontalStroke>
					<mx:verticalStroke>{lineStroke}</mx:verticalStroke>
				</mx:GridLines>
			</mx:backgroundElements>
			
			<mx:annotationElements>
				<fx:Array>
					<charts:RangeSelector id="selectedRange" />
				</fx:Array>
			</mx:annotationElements>
			
		</mx:LineChart>
		
	</s:VGroup>
	
</s:WindowedApplication>

DataTipSkin.mxml

'
<?xml version="1.0" encoding="utf-8"?>
<s:Group  xmlns:fx="http://ns.adobe.com/mxml/2009" 
		 xmlns:s="library://ns.adobe.com/flex/spark"  
		 implements="mx.core.IFlexDisplayObject, mx.core.IDataRenderer"
		 xmlns:mx="library://ns.adobe.com/flex/mx" width="120">
	
	<fx:Script>
		<![CDATA[
			import flashx.textLayout.conversion.TextConverter;
			import flashx.textLayout.elements.TextFlow;
			
			import mx.charts.HitData;
			import mx.charts.series.items.LineSeriesItem;
			
			private var _data:HitData;
			
			[Bindable]
			private var _xValue:String;
			
			[Bindable]
			private var _yValue:String;
			
			[Bindable]
			private var _displayText:TextFlow;
			
			public function get data():Object
			{
				// TODO Auto Generated method stub
				return null;
			}
			
			public function set data(value:Object):void
			{
				// HitData data from chart
				_data = value as HitData;
				
				// The display text used in datatip which comes in HTML format
				_displayText = TextConverter.importToFlow(_data.displayText, TextConverter.TEXT_FIELD_HTML_FORMAT);
				
				// HitData contains a reference to the ChartItem
				var item:LineSeriesItem = _data.chartItem as LineSeriesItem;
				
				// ChartItem xValue and yValue 
				_xValue = String(item.xValue);
				_yValue = String(item.yValue);
			}
		]]>
	</fx:Script>
	
	<fx:Declarations>
		
	</fx:Declarations>
	
	<s:Rect right="0" left="0" bottom="0" top="0">
		<s:filters>
			<s:DropShadowFilter blurX="20" blurY="20" alpha="0.22" distance="5" angle="90" knockout="false" />
		</s:filters>
		<s:fill>
			<s:SolidColor color="0x393939"/>
		</s:fill>    
		<s:stroke>
			<s:SolidColorStroke color="0x1a1a19"  weight="1" alpha=".2" />
		</s:stroke>
	</s:Rect>
	
	<s:VGroup width="100%" height="100%" paddingTop="10" paddingRight="10" paddingBottom="10" paddingLeft="10">
		
		<s:RichEditableText textFlow="{_displayText}" width="100%" textAlign="center" selectable="false" editable="false"/>
		
	</s:VGroup>

</s:Group>

-Mister

Flex Spark Rounded Image and Image Button Controls

I had the pleasure recently of collaborating with Ken Rogers (@pixels4nickels) on a couple of components. I had the need, and probably everyone has at one time or another, of having a image with rounded corners. My other desire was to have an image behave like a button.

So we came up with two components, one is called RoundedImage, this does pretty much what it advertises. It extends the Flex Spark Image control to set a corner radius of the loaded image. The other component is called ImageButton. This extends the Spark Button control and loads an image to create a button with rounded corners, pretty straight forward.

What makes these components nice is that they maintain the aspect ratio of the loaded image by simply setting either a height or width. So if you have a large image and want to scale it proportionally, you just set the width, the height will be scaled maintaining the aspect ratio. If you set both height and width values the loaded image will stretch to fit the dimensions.

Here is a screen shot of the results when setting with, height, or both:

You can take a look at the code for the Rounded Image and the Image Button at the following Gist links:

Michael Ritchie Gist: https://gist.github.com/1627989
Ken Rogers Gist: https://gist.github.com/1625442
Flex FXP File: http://thanksmr.com/examples/imagebuttons/ImageButtons.fxp

Big thanks to Ken for his help working out all the kinks and keeping it simple!

-Mister

Determining local timezone in ActionScript (AIR, Flex, AS3)

I made a little utility class that determines the local timezone (PST, EST, MST, CST, etc.). The guts of the utility are three methods, one for determining if the local machine is currently observing daylight savings time, another determines the GMT time from the the local machines current Date, and one for looking up the timezone abbreviation by GMT time. This is sort of a conglomerate of code that I could find on different posts and leveraged them to achieve my own goals.

Determining if the daylight savings time is currently being observed.

**
* Determines if local computer is observing daylight savings time for US and London.
* */
public static function isObservingDTS():Boolean
{
     var winter:Date = new Date(2011, 01, 01); // after daylight savings time ends
     var summer:Date = new Date(2011, 07, 01); // during daylight savings time
     var now:Date = new Date();

     var winterOffset:Number = winter.getTimezoneOffset();
     var summerOffset:Number = summer.getTimezoneOffset();
     var nowOffset:Number = now.getTimezoneOffset();

     if((nowOffset == summerOffset) && (nowOffset != winterOffset)) {
          return true;
     } else {
          return false;
     }
}

Creating the GMT from a Date object and adjusting for daylight savings time.

/**
* Method to build GMT from date and timezone offset and accounting for daylight savings.
*
* Originally code befor modifications:
* http://flexoop.com/2008/12/flex-date-utils-date-and-time-format-part-i/
* */
private static function buildTimeZoneDesignation( date:Date, dts:Boolean ):String
{
     if ( !date ) {
          return "";
     }

     var timeZoneAsString:String = "GMT";
     var timeZoneOffset:Number;

     // timezoneoffset is the number that needs to be added to the local time to get to GMT, so
     // a positive number would actually be GMT -X hours
     if ( date.getTimezoneOffset() / 60 > 0 && date.getTimezoneOffset() / 60 < 10 ) {
          timeZoneOffset = (dts)? ( date.getTimezoneOffset() / 60 ):( date.getTimezoneOffset() / 60 - 1 );
          timeZoneAsString += "-0" + timeZoneOffset.toString();
     } else if ( date.getTimezoneOffset() < 0 && date.timezoneOffset / 60 > -10 ) {
          timeZoneOffset = (dts)? ( date.getTimezoneOffset() / 60 ):( date.getTimezoneOffset() / 60 + 1 );
          timeZoneAsString += "+0" + ( -1 * timeZoneOffset ).toString();
     } else {
          timeZoneAsString += "+00";
     }

     // add zeros to match standard format
     timeZoneAsString += "00";
     return timeZoneAsString;
}

Finally, parsing the abbreviation from a simple lookup Array object.

/**
* List of timezone abbreviations and matching GMT times.
* Modified form original code at:
* http://blog.flexexamples.com/2009/07/27/parsing-dates-with-timezones-in-flex/
* */
private static var timeZoneAbbreviations:Array = [
     /* Hawaii-Aleutian Standard/Daylight Time */
     {abbr:"HAST", zone:"GMT-1000"},
     {abbr:"HADT", zone:"GMT-0900"},
     /* Alaska Standard/Daylight Time */
     {abbr:"AKST", zone:"GMT-0900"},
     {abbr:"ASDT", zone:"GMT-0800"},
     /* Pacific Standard/Daylight Time */
     {abbr:"PST", zone:"GMT-0800"},
     {abbr:"PDT", zone:"GMT-0700"},
     /* Mountain Standard/Daylight Time */
     {abbr:"MST", zone:"GMT-0700"},
     {abbr:"MDT", zone:"GMT-0600"},
     /* Central Standard/Daylight Time */
     {abbr:"CST", zone:"GMT-0600"},
     {abbr:"CDT", zone:"GMT-0500"},
     /* Eastern Standard/Daylight Time */
     {abbr:"EST", zone:"GMT-0500"},
     {abbr:"EDT", zone:"GMT-0400"},
     /* Atlantic Standard/Daylight Time */
     {abbr:"AST", zone:"GMT-0400"},
     {abbr:"ADT", zone:"GMT-0300"},
     /* Newfoundland Standard/Daylight Time */
     {abbr:"NST", zone:"GMT-0330"},
     {abbr:"NDT", zone:"GMT-0230"},
     /* London Standard/Daylight Time */
     {abbr:"BST", zone:"GMT+0100"},
     {abbr:"GMT", zone:"GMT+0000"}
];

/**
* Goes through the timze zone abbreviations looking for matching GMT time.
* */
private static function parseTimeZoneFromGMT(gmt:String):String
{
     for each (var obj:Object in timeZoneAbbreviations) {
          if(obj.zone == gmt){
               return obj.abbr;
          }
     }
     return gmt;
}

This utility is obviously not robust enough to do world timezones, but its enough of a framework to work with if you want to expand past just US timezones (and London). I am sure there are a lot of different ways this could be improved, so please share resources or ideas if you have them. You can get the code for the complete utility from GitHub:

TimzeZoneUtil.as

Thanks!

-Mister

Spark Button and ButtonBar with icons and rollover states

The Flash Builder Spark Button control doesn’t come with an icon property out of the box. So you have to extend the Button class and add your own. I created a Spark Skin to add two icons to the Button control, one for the up/disabled state and one for the over/down states.

The Spark ButtonBar control does accommodate an icon, but there is no way to change the icon when the selected index changes. So to change the icon of the selected item, I built a Spark Skin for the ButtonBarButton and the ButtonBar to accomplish the job. Here is the running example of the buttons in action:

IconButtons.swf

The code of the IconButton class and the IconButtonSkin mxml file that accompanies the class:

https://gist.github.com/946886

And the code of the IconButtonBarButton class and the IconButtonBarSkin and IconButtonBarButtonskin mxml

https://gist.github.com/947130

You can also download the IconButtons Flash Builder Project.

-Mr

AS3 P2P Helper Class

This is just a simple class I created to allow to clients (AIR Desktop, AIR Mobile) to send and receive commands from each other using Flash Player 10 P2P (Peer to Peer). This class is used to drive a AIR application running on a large wall mounted flat screen monitor from an Android mobile device. These are two different applications but are talking to each other through this common library while connected on the same network.

There is a great little starter video by Paul Trani with CS5. Peter Elst is also working on a P2P library called Cocoon that allows more robust communication. Also check out Renaun Erickson’s post for setting up your Mac as a hub for local P2P connections without WiFi.

Full code: https://gist.github.com/673f0a77f701d4ae98a7

-Mister

Upload to S3 with cURL and AIR NativeProcess

This application demonstrates how to upload files to Amazon S3 (part of Amazon Web Services) with cURL from an Adobe AIR application using the AIR 2 NativeProcess API. This application uses the AIR 2.0 or higher SDK, Flash Builder 4, and the cURL native application for uploading files.

To use this application also depends on the as3corelib, as3awss3lib, and as3crypto libraries. You will also need an Amazon S3 developer account and have cURL installed on your system.

Why upload with cURL instead of AIR? Part of the problem with uploading through an AIR application, or any Flash application, is the size limit of the uploads (I think something like 100MB is the recommended size). What happens when you want to upload gigabytes of data? Offloading the uploading of large files to a native process solves this problem. You can also spawn multiple instances of the native process to do multiple uploads. This makes sure your AIR application continues to be responsive and performs well while the uploads happen in the background. Using something like cURL means you have a cross-platform native process that can be installed along with your application.

The main guts of the application revolve around assembling the correct cURL arguments to upload the files to the S3 service. This also requires properly creating an policy expected by S3 to complete the upload process. Here is the core code for creating the S3 policy file and the arguments for cURL:

/**
* Uploads a file to S3 using cURL using the AIR NativeProcess API.
*
* @param file File object
* */
protected function saveFile(folderid:String, file:File):void
{
createProgressPanel(); // add our progress bar

var cURL:File = File.applicationDirectory;

if (Capabilities.os.toLowerCase().indexOf("win") > -1) {
cURL = cURL.resolvePath("bin/curl.exe");
} else if (Capabilities.os.toLowerCase().indexOf("mac") > -1) {
cURL = cURL.resolvePath("/usr/bin/curl");
}

var contentType:String = "multipart/form-data";
var arguments:Vector. = getArguments("PUT", folderid, file, contentType);

var nativeProcessStartupInfo:NativeProcessStartupInfo = new NativeProcessStartupInfo();
nativeProcessStartupInfo.arguments = arguments;
nativeProcessStartupInfo.executable = cURL;

process = new NativeProcess();
process.addEventListener(ProgressEvent.STANDARD_INPUT_PROGRESS, onInputProgress);
process.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, onStandardOutputData);
process.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, onStandardErrorData);
process.addEventListener(NativeProcessExitEvent.EXIT, onStandardOutputExit);

process.addEventListener(IOErrorEvent.STANDARD_OUTPUT_IO_ERROR, onOutputIOError);
process.addEventListener(IOErrorEvent.STANDARD_ERROR_IO_ERROR, onStandardIOError);

process.start(nativeProcessStartupInfo);
}

/**
* Create the native process starupt info arguments. Be sure to check the cURL documentation
* for more functions on upload: http://curl.haxx.se/docs/manual.html
*
* @param method POST or GET arguements
* @param bucketname The S3 bucket name for upload target
* @param file File to upload
* @param contentType The mime type for the upload
* @param secure Boolean value for usting https or http
* @return Vector.
* */
protected function getArguments(method:String, bucketname:String, file:File, contentType:String = "multipart/form-data", secure:Boolean = false):Vector.
{
var protocol:String = (secure)? "https":"http";
var path:String = protocol + "://" + bucketname + "." + AMAZON_ENDPOINT
var policy:String = getPolicy(bucketname, contentType);

var arguments:Vector. = new Vector.();
arguments.push("-#"); // gives us a ### % ouput for progress from cURL
arguments.push("-F key=" + file.name );
arguments.push("-F AWSAccessKeyId=" + this.accessKey );
arguments.push("-F policy=" + policy );
arguments.push("-F signature=" + getSignature( policy) );
arguments.push("-F Content-Type=" + contentType);
arguments.push("-F file=@" + file.nativePath);
arguments.push(path);

return arguments;
}

/**
* Creates the policy file for the S3 upload. For more information on AWS policy files:
* http://aws.amazon.com/articles/1434. The paramater content-length-range restricts
* the file upload size. Remove it if you want to have no restrictions on upload size.
* */
protected function getPolicy(bucketname:String, contentType:String):String
{
// date has to be some time in the future so uploads don't expire in progress
var obj:Object = {"expiration": "2015-06-15T12:00:00.000Z",
"conditions": [
{"bucket": bucketname},
["starts-with", "$key", ""],
["starts-with", "$Content-Type", ""],
["content-length-range", 0, 1048576]
]
}

var json:String = JSON.encode(obj);
var encoded: String = Base64.encode(json);

return encoded;
}

/**
* Craete the signature for S3. For more information on S3 signatures:
* http://aws.amazon.com/articles/1434
* */
protected function getSignature(policy:String):String
{
var policyBytes:ByteArray = new ByteArray();
policyBytes.writeUTFBytes(policy);

var secretAccessKeyBytes:ByteArray = new ByteArray();
secretAccessKeyBytes.writeUTFBytes(this.secretAccessKey);

var hmacBytes:ByteArray = hmac.compute(secretAccessKeyBytes, policyBytes);

return Base64.encodeByteArray(hmacBytes);
}

The tricky part was getting upload feedback from cURL in a format that we could use to display the upload progress. You might notice in the code above that we add an argument to cURL to output a % for uploads in progress. We need to parse this information when it comes back in from the ProgressEvent.STANDARD_ERROR_DATA event of the NativeProcess:

/**
* Handles writing within the process such as percent complete.
* */
protected function onStandardErrorData(event:ProgressEvent):void
{
var output:String = ( process.standardError.readUTFBytes(process.standardError.bytesAvailable) );
var regex:RegExp = /([0-9\.]+)/;
var exec:String = regex.exec(output);

if(exec) {
var arry:Array = exec.split(",");
var percent:Number = Math.round(Number(arry[0])); // save percent complete

if(percent > percentComplete) {
percentComplete = percent;
progressBar.setProgress(percentComplete, progressBar.maximum);
}
}
}

The AIR application installer file and the full code for this example can be found at the GitHub repository:

AWSS3cURL

Additional Resources
Amazon Dev Article on Form Post Upload
Amazon S3 Forum discussion on cURL
cURL
Amazon S3 Manager

– Mister

Custom AIR Applicaton Updater for Flex 4 with Spark Skins

In a previous post I laid out the code for a custom application updater for AIR projects. I have since updated that project to work with Flex 4, including Spark controls and skins. It’s currently skinned to look like the default updater in Flash Builder.

I ran into a strange issue when moving the project from Flex 3 to Flex 4 (SDK 4.1) and wasn’t initially able to read the update.xml file that lives on the server. I had to change both the namespace and add “versionNumber” to the xml file to work with an AIR 2.5 project.

update.xml

<?xml version="1.0" encoding="utf-8"?>
<update xmlns="http://ns.adobe.com/air/framework/update/description/2.5">
  <versionNumber>2.0.0</versionNumber>
  <url>app:/server/UpdateTester.air</url>
  <description>
    <![CDATA[Version 2:
        * Testing the update feature.
        * More testing and bug fixes, bla, bla, bla.]]>
  </description>
</update>

The entire project is on GitHub. Just download and import it into Flash Builder 4. Remember the application won’t actually update from the IDE, so it will give an error if you try to actually download the update.

CustomApplicationUpdate

-Mister

AIR for Android: Phoenix Traffic Released in Android Market


Phoenix Traffic for Android

I finally released my first application into the Android Market. This application takes data for Phoenix traffic cameras and displays live camera images. That part was simple enough, but deciding to go with either Flex or Flash for development was the hard part. Originally, I built the application using Flex 4 (this was pre-Hero and Burrito) and talked about it in a previous post. However, I found the Flex application to be memory intensive, lethargic, and the scrolling list functionality simply unusable.

For the final release of the application, I decided to use Flash CS5. This allowed me to build a somewhat smaller version of the application that could be easily be deployed using Adobe’s AIR technology for Android directly from Flash. As part of this project I built (or rather modified code from others) an AS3 scrolling list that responds to touch events and behaves similar to native Android scrolling lists.

In my opinion, the list still performs better than some of the current controls in being built for Flex Burrito. This might change in the near future, but for now, AS3 only applications on Android seem to be lighter and perform better than Flex. If you are interested, you can see the code and example files for the scrolling list here in this post.

To download the Phoenix Traffic application, you can visit the Phoenix Traffic application page from this site or just search for “Phoenix Traffic” in the Android Market. Please feel free to leave me any comments or feedback about the application. I will continue to tinker with the application and improve it over time.

Update

This application has since been migrated from AIR to a native Android application.

– Mister

AS3 Scrolling List for Android and iOS devices

I created a very simple AS3 list that works with the both Android and iOS devices. The project files include a Flash Professional project created with Flash Builder 4. You will need Adobe AIR for Android or the packager for iPhone to create naive create native iOS (iPhone, iPad) or Android.

If you only want to build for Android, then I recommend you check out Adobe Flash Builder Burrito and the Flex Hero SDK (or SDK 4.5). There is already a list control in the Flex Hero SDK (or SDK 4.5) for Android devices. However for iOS devices, you will need a scrolling list that works with AS3 and CS5 for packaging.

The list I created is an AS3 list that works for multiple devices, touch scrolls, and uses custom item renderers that detect user interaction. Here is an example AS3 project with the list in action. Just use your mouse like you would your finger on a mobile device to scroll the list and select items.



AS Scrolling List (click to view)

The list is suited best for smaller sets of data because the list does not recycle list items. But for most mobile applications you don’t normally have that many items to scroll. Adobe also recommends that you not use the drawing API in Flash because of its memory consumption on mobile devices. It would be better to create a MovieClip or Sprite in Flash and use that as the background of your item renderer. However, int this project I used the drawing API to change the selection color of the list item throwing all caution to the wind.

TouchList

The TouchList class creates the list, adds items and handles touch events dispatched by the item renderers. You might notice that I didn’t use any actual TouchEvent listeners in the list. This is because a TouchEvent is essentially a MouseEvent and I couldn’t see any difference in using one over the other. The TouchList class has a built in delay to differentiate between a scrolling and touch action. Like the Android phone, you can’t select an item while scrolling and pressed items are deselected if you scroll while pressed.

TouchListItemRenderer

TouchListItemRenderer implements ITouchListItemRenderer and renders the display of the items in the list data. This renderer can be customized to show whatever type of data you want in the list. List items can also be variable height.

ITouchListItemRenderer

If you want to create an item renderer for the list, then it must implement the ITouchListItemRenderer interface. This interface gives the renderer basic functionality to interact with user selection and touch events used by the list.

ListItemEvent

The list item event is a custom custom ListItemEvent dispached when a list item renderer is pressed. The event contains the event payload and a instance of the item renderer selected.

Installation

Included in the GitHub repository is the working project files for that I created in Flash Builder 4 that handles adding the list to the stage, screen orientation on the device, stage resize, and other functions for an Android AIR application. To install, just checkout the project file and import it into Flash Builder. I have also included Android .apk file if you want to deploy it directly to your Android phone.

The AS3ScrollinList project is located on GitHub.

If you do use the list in a project, be sure to drop me a note or mention me in your will. This list is actually a combination of my efforts and those of others in the Flash community. So please share what you build as well. If you have improvements, just post them back to this post or feel free to fork the GitHub code.

Work Cited

-Mister

Phoenix Traffic Android Mobile Application built with AIR

UPDATE 4/04/2012
The application has been migrated from Adobe AIR for Android to a native Android application. Still available in the market under the same name.

UPDATE
I recently released the Phoenix Traffic application on the Android market. The application was built using CS5 rather than Flex. I also created my own custom scrolling list that works in AS3 for iPhone and Android. You can find out more on this post:

Phoenix Traffic Released in Android Market

AS3 Scrolling List for Android and iOS

Original Post

I developed a simple Flex 4 application targeting AIR for Android. For this application, I used Flex to build a somewhat smaller version of a previous application that uses XML data to display a list Phoenix traffic cameras locations and images. The images are updated on an set interval and locations are selected from a list of freeways and intersections for each traffic camera.

Initially, I built the application in Flash, but ran into some issues and annoyances with creating a proper list that worked with the Multitouch events for capturing user gestures on multitouch devices like Android.

The Flex 4 list has support for TouchEvent. However, it’s still difficult to differentiate between the different TouchEvent’s being fired (TouchEvent.TOUCH_BEGIN, TouchEvent.TOUCH_MOVE, TouchEvent.TOUCH_END, TouchEvent.TAP). As a result, the list has a tendency to select items while scrolling the list.

Here are some screen shots of the application running on my NexusOne:

 

The Flex preloader was replaced with a simple splash screen graphic.

Simple list of freeways.

Once you select a freeway, you see list of camera locations for that freeway.

Selecting a camera takes displays the live camera image accompanied by two still images for direction.

This was my first run at doing Android and I can see some potential. Deploying AIR application from Flex 4 to your Android device is pretty easy, though nothing like the experience publishing from Flash CS5. The applications tend to be a little robust, hopefully this will be resolved with the release of the Halo components which are designed specifically for mobile devices.

To build your own AIR for Android applications, you need an Android device running Android 2.2 which supports Flash Player 10.1 and AIR. you also need to sign up for the AIR for Android Prerelease program. There are some good example applications with code starting to appear, including a scrolling list. Here are the posts I referenced used building this application:

Flex 4 List Scrolling on Android with Flash Player 10.1
“VoiceNotes for Android”: Sample App using Flex, AIR, and the Microphone API
AIR on Android: TweetrApp Video walk-through
Employee Directory Sample Application Using Flex and AIR for Android – Updated for Froyo
Flex 4 Application Handling Touch Events on Android with Flash Player 10.1

– Mister