You have those times when you get an idea, so you sit down and start building it? You know, maybe you are a designer, and that means cracking up Flash Pro CS5. Or perhaps you are a developer and you start messing with item renderers. As I travel around from conference to conference, I get a lot of ideas like that. And for most of them, I either run out of steam, get distracted, or simply get bored. Over the next several weeks I’ll be dropping projects like that on the old blog – starting with these Flash components that look like Android.
I wanted to get to know Android – intimately. So I started examining the user interface controls. At first this was mostly on the device, to get a feel for the types of controls that were available, and the way they transitioned states. Next I started using the “ddms” screen capture utility that comes with the Android SDK to get a closer look at the pixels. I’d get the screen to a state I wanted, capture it, and then dissect it using Fireworks CS5. Finally, I started reassembling the controls in Flash Pro CS5 and putting ActionScript logic behind them.
The result is a pretty performant, and decent foundation of controls that look and feel like Android, but are done all with Flash, and expected to be deployed using AIR for Android. I could go a lot further with these, but then again, there’s that running out of steam thing. For example, these are really designed for the NexusOne – I don’t account for screen density. I also don’t account for screen orientation, though there’s hooks in the components for some basic sizing.
Okay, enough about what’s not there, what is there?
- Button
- CheckBox
- ComboBox
- DateChooser
- Footer
- Label
- List
- Menu
- NumericStepper
- TextInput
- TimeChooser
- Title
Some of these components need additional explanation. For example, the “DateChooser”. Most of the dates in Android are presented via a modal dialog box. Mine is no different. Though I don’t call them out as components in the above list, there’s stepper controls used by the dialog to control month, date and year. Likewise for the “TimeChooser” where you will find controls for the hour and minute.
“Footer” is the bar you find at the bottom of most Android forms. The Footer control accepts up to three strings, that will give you up to three buttons. Why three? Well, because that’s the most I saw in use on any Android application. The “Title” is the gray bar you see at the top of most Android forms. The “Menu” takes up to six buttons, and shows up at the bottom of the screen when you use the hard menu button on the device.
Regardless of the component, they are designed to be pretty atomic, and although they were designed in Flash Pro CS5, then can easily be used in Flash Builder 4 from an ActionScript project, because I include a SWC in the build. Here’s some example code, and the result user interface. In short, you instantiate the control you want, position it and size it if necessary, and then add it to the stage. Register for any events you may want to drive the rest of the application at runtime.
package
{
import flash.display.Sprite;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.events.MouseEvent;
public class Components extends Sprite
{
private var btn:Button = null;
private var chk:CheckBox = null;
private var cmb:ComboBox = null;
private var day:DatePicker = null;
private var ftr:Footer = null;
private var lbl:Label = null;
private var listing:ListPicker = null;
private var opt:OptionPicker = null;
private var time:TimePicker = null;
private var mnu:Menu = null;
private var tme:Button = null;
private var ttl:Title = null;
private var txt:TextInput = null;
public function Components()
{
super();
init();
}
private function init():void
{
var btnx:Button = null;
var lblx:Label = null;
var today:String = DateDialog.formatShort( new Date() );
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
ttl = new Title( "Event details" );
addChild( ttl );
lbl = new Label( "What" );
lbl.x = 9;
lbl.y = 52;
addChild( lbl );
txt = new TextInput( "Event name" );
txt.x = 9;
txt.y = 85;
addChild( txt );
lblx = new Label( "From" );
lblx.x = 9;
lblx.y = 170;
addChild( lblx );
btn = new Button( today, 282, Button.TRIGGER );
btn.x = 14;
btn.y = 203;
btn.addEventListener( MouseEvent.CLICK, doDateClick );
addChild( btn );
tme = new Button( "1:00pm", 158, Button.TRIGGER );
tme.x = 306;
tme.y = 203;
tme.addEventListener( MouseEvent.CLICK, doTimeClick );
addChild( tme );
lblx = new Label( "To" );
lblx.x = 9;
lblx.y = 276;
addChild( lblx );
btnx = new Button( today, 282, Button.TRIGGER );
btnx.x = 14;
btnx.y = 309;
addChild( btnx );
btnx = new Button( "2:00pm", 158, Button.TRIGGER );
btnx.name = "to";
btnx.x = 306;
btnx.y = 309;
addChild( btnx );
chk = new CheckBox();
chk.x = 416;
chk.y = 396;
chk.addEventListener( MouseEvent.CLICK, doCheckClick );
addChild( chk );
cmb = new ComboBox( "Home" );
cmb.x = 13;
cmb.y = 487;
cmb.addEventListener( MouseEvent.CLICK, doComboClick );
addChild( cmb );
ftr = new Footer( "Done", "Revert" );
ftr.y = 680;
addChild( ftr );
mnu = new Menu( [
{path: "search.png", label: "One"},
{path: "search.png", label: "Two"},
{path: "search.png", label: "Three"},
{path: "search.png", label: "Four"},
{path: "search.png", label: "Five"},
{path: "search.png", label: "Six"}
] );
mnu.addEventListener( MenuEvent.CLICK, doMenuClick );
addChild( mnu );
day = new DatePicker();
day.addEventListener( DialogEvent.OK, doDateOk );
day.addEventListener( DialogEvent.CANCEL, doDialogCancel );
addChild( day );
time = new TimePicker();
time.addEventListener( DialogEvent.OK, doTimeOk );
time.addEventListener( DialogEvent.CANCEL, doDialogCancel );
addChild( time );
listing = new ListPicker();
listing.addEventListener( ListEvent.CLICK, doListingClick );
addChild( listing );
}
protected function doCheckClick( event:MouseEvent ):void
{
var btnx:Button = null;
if( chk.selected )
{
tme.visible = false;
btn.setWidth( 450 );
} else {
tme.visible = true;
btn.setWidth( 282 );
}
}
protected function doComboClick( event:MouseEvent ):void
{
listing.show( [
"Default ringtone", "Backroad", "Bell Phone", "Big Easy",
"Bird Loop", "Bollywood", "Bus' a Move", "Cairo",
"Calypso Steel", "Champagne Edition", "Chimey Phone",
"Club Cubano", "Crayon Rock", "Curve Ball Blend", "Dancin Fool",
"Digital Phone", "Ding", "Don' Mess Wiv It", "Eastern Sky",
"Enter the Nexus", "Ether Shake", "Flutey Phone", "Free Flight",
"Funk Y'all", "Gimme Mo' Town", "Glacial Groove", "Growl",
"Halfway Home", "Loopy Lounge", "Los Angeles, 2019",
"Love FLute", "Medieval Jaunt", "Mildly Alarming", "Nairobi",
"Nassau", "No Limits", "Organ Dub", "Paradise Island", "Playa",
"Radiation by Spagnola", "Road Trip", "Safari", "Seville",
"She's All That", "Silky Way", "Steppin' Out", "Terminated",
"Third Eye", "Twirl Away", "World"],
"Ringtones"
);
}
protected function doDialogCancel( event:DialogEvent ):void
{
trace( "Dialog cancel." );
}
protected function doDateClick( event:MouseEvent ):void
{
day.show( new Date() );
}
protected function doDateOk( event:DialogEvent ):void
{
btn.label = DateDialog.formatShort( day.date );
}
protected function doListingClick( event:ListEvent ):void
{
cmb.label = event.label;
}
protected function doMenuClick( event:MenuEvent ):void
{
trace( event.label );
}
protected function doTimeClick( event:MouseEvent ):void
{
time.show( new Date() );
}
protected function doTimeOk( event:DialogEvent ):void
{
tme.label = TimeDialog.formatShort( time.time );
}
}
}






Again, I want to note that this is a random idea project. It’s pretty modular, but may not be to the liking of many. The package structure is totally flat, though I suppose that’s a nit-pick more than a problem. If you are thinking that I should have skinned Keith Peters’ Minimal Comps, you’re probably right, but I started this on a plane, and it grew from there before Keith’s components could be skinned. All of it is available for download. If you find it useful, or have any questions about the architecture, don’t hesitate to ask.