Air Mobile :: Hello BusyIndicator take 1
The BusyIndicator defines a component to display when a long-running operation is in progress.
What is the BusyIndicator
The BusyIndicator is a UIComponent that plays an animation while a background operation is running to alert the user of indeterminate progress. The BusyIndicator by default draws twelve spokes that set each spoke’s alpha in intervals of about 0.1 foreach rotation interval. This gives the illusion that the indicator is spinning.
Metrics
- 160 DPI – 26×26 pixels
- 240 DPI 40×40 pixels
- 320 DPI 52×52 pixels
It’s important to note that the above dimensions are measured. If the width and height are increased or decreased, the component will fill the minimum of the two.
What Is The BusyIndicator Used For
As mentioned, the BusyIndicator is used to notify the user of a long running operation. This component due to the way it was programmed is not very "extendable". Most of the internal methods are private or mx_internal meaning as a responsible developer you cannot even override the draw logic without opening up the mx_internal namespace.
The BusyIndicator could be used in a modal PopUpContainer to disallow user interaction while the operation is in progress. The BusyIndicator could be placed within the ActionBar to notify the user in a less obtrusive nature. The BusyIndicator could just be placed on top of ViewNavigator View instances to act as a non interuptive progress targeting the View that is loading data.
With either of the options listed above it’s important to note that the BusyIndicator is just a plain old UIComponent under the covers. This means it’s a standard display object that can be placed where ever needed.
How to Sart And Stop The Rotation
Starting and stopping the rotation is out of the hands of the developer. The component listens for ADDED_TO_STAGE and REMOVED_FROM_STAGE events to start and stop it’s animation.
How To Style The BusyIndicator
The BusyIndicator has two styles;
rotationInterval:Number– In milliseconds that amount of relative spin given to the indicator.symbolColor:uint– The color of the indicator’s spokes.
Getting Started with The With The BusyIndicator :: Take1
To start using the BusyIndicator, it’s as easy as placing the component in MXML or instantiating the component and adding it to the display list through ActionScript. Since the docs talk about that lets try some other strategies and see what we come up with.
Take 1 involves a newer developers take on the "touted" Spark skinning system and hey "just skin it!" attitude. The problem with skinning a component like the SkinnablePopUpContainer is the fact the default skin has 110 lines of MXML code in it that we copy.
Note: It is assumed with the plethora of mobile tutorials out there that you know how to create Flex Mobile projects and understand how to create custom components.
Step 1: Create a new mobile application
- Create and setup a new Flex Mobile Project using the View-Based Application template:
HelloBusyIndicatior- Name the view Take1
Step 2: Create a new SkinnablePopUpContainer skin
- Create a new MXML Skin named
BusyPopUpSkin- File > New > MXML Skin
- Fill in the inputs as listed below

- With the BusyPopUpSkin.mxml open add the
BusyIndicatorcomponent to thecontentGroup
... <s:Group id="contentGroup" left="0" right="0" top="0" bottom="0" minWidth="0" minHeight="0"> <s:layout> <s:BasicLayout/> </s:layout> <s:BusyIndicator id="busyIndicator" verticalCenter="0" horizontalCenter="0"/> </s:Group> ...
What we have done here is added the indicator to the content of the SkinnablePopUpContainer so when it is created, the BusyIndicator is automtaically running and centered within the popup.
Step 3: Create the code that will use the PopUp
- Go back to the Take1.mxml View and replace the code with the following
<?xml version="1.0" encoding="utf-8"?> <s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" title="Take1"> <fx:Script> import skins.BusyPopUpSkin; import spark.components.SkinnablePopUpContainer; private var mTimer:Timer; private var mPopUp:SkinnablePopUpContainer; protected function button1_clickHandler(event:MouseEvent):void { // if busy, return if (mPopUp) return; createPopUp(); startOperation(); } private function createPopUp():void { // create the SkinnablePopUpContainer mPopUp = new SkinnablePopUpContainer(); // set the styles mPopUp.setStyle("skinClass", BusyPopUpSkin); mPopUp.setStyle("backgroundColor", 0x000000); mPopUp.setStyle("backgroundAlpha", 0.3); layoutPopUp(); // call PopUpManger to open and add mPopUp.open(this); positionPopUp(); } private function layoutPopUp():void { // match the popups width, height to the View mPopUp.width = width; mPopUp.height = height; } private function positionPopUp():void { // use the View x, y coords var point:Point = new Point(x, y); // convert the View x,y to global so this can be laid out in nested Views point = parent.localToGlobal(point); // set the popup's global x,y coords mPopUp.x = point.x; mPopUp.y = point.y; } private function startOperation():void { mTimer = new Timer(3000, 1); mTimer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler); mTimer.start(); } private function endOperation():void { mPopUp.close(); mPopUp = null; } private function timerCompleteHandler(event:TimerEvent):void { mTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler); mTimer = null; endOperation(); } </fx:Script> <s:layout> <s:VerticalLayout horizontalAlign="center" paddingTop="50"/> </s:layout> <s:actionContent> <s:Button id="initiateButton" label="Set Busy" click="button1_clickHandler(event)"/> </s:actionContent> <!-- This button will not be touchable when the indicator is present --> <s:Button label="Can't touch this! :)"/> </s:View>
Whats going on in that code?
- A
Buttonwas added to theactionContentof theActionBarto trigger the creation of the popup. - A handler was added to create the popup and start the progress operation.
- The
createPopUp()method creates an newSkinnablePopUpContainerand sets it’sskinClass, this is how the skin is applied in this version.- The
backgroundColorandbackgroundAlphastyles are there to show how to adjust the popups background.
- The
- The
layoutPopUp()assigns a newwidthandheightbased on theView'swidthandheight. - The popup is then opened using the
open()method that calls the PopUpManager. - The
positionPopUp()method takes theView'sx, y coords and translates them to global coords so the popup will be placed directly on top of theView.- This in effect creates a poor mans modal over the
View.
- This in effect creates a poor mans modal over the
- The
startOperation()method simulates a long running operation that in this case runs three seconds and calls the popupsclose()to dismiss the popup.
Step 4: Run the application

Conclusion
Well, looks the the BusyIndicator is a capable little component of display a familiar interface to mobile users. Do you see anything wrong with Take 1 of the BusyPopUp ?
I do and here are my thoughts;
- Using a skin for this implementation is not good. Spaghetti code for 1 line of added content.
- All of the logic for the popup is in a
Viewclass, no good, remember separation of duties in design patterns 101? - There is no way of adding any type of textual information to let the user know what is going on. (yes we could have easily put a Label in the contentGroup, how to get to it?)
What to do about this;
- Take 2 will consist of a component developers implementation on solving the above problems.
- Create a
BusyLabelPopUpcomponent that subclassesSkinnablePopUpContainer.- This will remove all logic from the view.
- Use the
partAdded()method of the new component to add aBusyIndicatorandLabelcomponent to thecontentGroup.- This will remove the need for duplicating the skin when in this case there is really no need for a custom skin.
- Add a property
statuson the new component so real time textual updates are possible through theBusyLabelPopUppublic interface. - Override the
updatePopUpPosition()of theBusyLabelPopUpto apply the layout logic of the popup over the owner.
I went out of my way to make a crappy implementation first, so you can learn from the worst.
In these new times of mobile, applications need to be abstract and decoupled because the likelihood of wanting to reuse code and components increase by a factor of 100.
Take 2 will be published shortly showing the proper creation of components and api.
About the Author
Michael Schmalle has been developing Adobe Flex and the Flash Player since Flash version 5 (2002). He has numerous open source projects in ActionScript3 (including an ActionScript3 parser/lexer DOM for reading and writing AS3 source code) and Flex (user interface components). He has also been an active participant in the Flex community (just goolge him or Teoti Graphix, LLC) since 2004. He also realizes technologies change and is actively developing user interface components and applications on the Google Android mobile platform.
See Teoti Graphix. LLC.
GIT: https://github.com/teotigraphix
Twitter: http://twitter.com/TeotiGraphix/
Recent Comments