AIR Mobile :: Hello BusyIndicator take 2

December 5th, 2011 Michael Schmalle 2 comments

This article is Take 2 on the last article discussing the BusyIndicator.

"A good component developer breaks things into pieces, smashing them on the floor, putting the parts back into classes" ;-)

See Air Mobile :: Hello BusyIndicator take 1

What Needs To Be Fixed

  • Ditch the BusyPopUpSkin and use a special curcumstance partAdded() implementation for adding skinparts.
  • Move popup layout logic to custom component class.
  • Add ability to notify user of updates through a status interface on the component.

The new component;

Note: These articles you read of mine are going to show you the things that a lot of tutorials don’t. I have years of experience making components and know one thing, do what your heart tells you to do, not what the book says. You need experience, but once you have it, walk your own path and make it work the way it should not how it is supposed to work. :)

Let’s start off by looking at the BusyLabelPopUp custom component’s code; (yes read it before continuing)

package components
{
 
import flash.geom.Point;
 
import spark.components.BusyIndicator;
import spark.components.Label;
import spark.components.SkinnablePopUpContainer;
import spark.layouts.HorizontalAlign;
import spark.layouts.VerticalAlign;
import spark.layouts.VerticalLayout;
 
/**
 * A PopUp that contains a BusyIndicator and Label for status updates.
 * 
 * @author Michael Schmalle
 * @copyright Teoti Graphix, LLC
 * @productversion 1.0
 */
public class BusyLabelPopUp extends SkinnablePopUpContainer
{
	//--------------------------------------------------------------------------
	// 
	//  SkinPart :: Variables
	// 
	//--------------------------------------------------------------------------
 
	//----------------------------------
	//  busyIndicator
	//----------------------------------
 
	[SkinPart(required="false")]
 
	/**
	 * The busy indicator that notifies the user of indeterminate progress.
	 */
	public var busyIndicator:BusyIndicator;
 
	//----------------------------------
	//  statusDisplay
	//----------------------------------
 
	[SkinPart(required="false")]
 
	/**
	 * The Label that will display the status message if any.
	 */
	public var statusDisplay:Label;
 
	//--------------------------------------------------------------------------
	// 
	//  Public :: Properties
	// 
	//--------------------------------------------------------------------------
 
	//----------------------------------
	//  status
	//----------------------------------
 
	/**
	 * @private
	 */
	private var statusChanged:Boolean = false;
 
	/**
	 * @private
	 */
	private var _status:String;
 
	/**
	 * Sets the status message on the popup.
	 */
	public function get status():String
	{
		return _status;
	}
 
	/**
	 * @private
	 */
	public function set status(value:String):void
	{
		if (_status == value)
			return;
 
		_status = value;
 
		statusChanged = true;
		invalidateProperties();
	}
 
	//--------------------------------------------------------------------------
	// 
	//  Constructor
	// 
	//--------------------------------------------------------------------------
 
	/**
	 * Constructor.
	 */
	public function BusyLabelPopUp()
	{
		super();
	}
 
	//--------------------------------------------------------------------------
	// 
	//  Overridden Public :: Methods
	// 
	//--------------------------------------------------------------------------
 
	override public function updatePopUpPosition():void
	{
		// use the owner x, y coords
		var point:Point = new Point(owner.x, owner.y);
		// convert the owner x,y to global so this can be laid out in 
		// nested Views
		point = owner.parent.localToGlobal(point);
		// set the popup's global x,y coords
		x = point.x;
		y = point.y;
		// mirror the owner's width and height onto the popup
		width = owner.width;
		height = owner.height;
	}
 
	//--------------------------------------------------------------------------
	// 
	//  Overridden Protected :: Methods
	// 
	//--------------------------------------------------------------------------
 
	override protected function partAdded(partName:String, instance:Object):void
	{
		super.partAdded(partName, instance);
 
		if (instance == contentGroup)
		{
			// if the contentGroup has 0 children right now, we know 
			// a custom skin was not applied and we should create the 
			// skinparts programatically
			// this is being 'polite' to future devs that may need an
			// MXML skin implementation adding skinparts declarativly
			if (contentGroup.numElements == 0)
			{
				// update layout knowing we are adding composite skinparts
				updateLayout();
				// create the busyIndicator skinpart
				createBusyIndicator();
				// create the statusDisplay skinpart
				createStatusDisplay();
			}
		}
	}
 
	override protected function commitProperties():void
	{
		super.commitProperties();
 
		if (statusChanged)
		{
			// this is optional but smart, create a commit method so your
			// devs that follow have a hook to change your code down the road
			commitStatus();
			statusChanged = false;
		}
	}
 
	//--------------------------------------------------------------------------
	// 
	//  Protected :: Methods
	// 
	//--------------------------------------------------------------------------
 
	protected function updateLayout():void
	{
		// create a nice and simple VerticalLayout that centers both parts
		// in the full layout. Remeber that the skin sets all layout
		// constraints to 0, effectively saying width=100%, height=100%
		var vlayout:VerticalLayout = new VerticalLayout();
		vlayout.horizontalAlign = HorizontalAlign.CENTER;
		vlayout.verticalAlign = VerticalAlign.MIDDLE;
		vlayout.gap = 10;
		layout = vlayout;
	}
 
	protected function createBusyIndicator():void
	{
		// this could also be a factory, for simplicity we create here
		// this is really no different than what the mobile skins do
		busyIndicator = new BusyIndicator();
		// setting the id allows CSS #busyIndicator
		busyIndicator.id = "busyIndicator";
		contentGroup.addElement(busyIndicator);
	}
 
	protected function createStatusDisplay():void
	{
		// this could also be a factory, for simplicity we create here
		// this is really no different than what the mobile skins do
		statusDisplay = new Label();
		// setting the id allows CSS #statusDisplay
		statusDisplay.id = "statusDisplay";
		contentGroup.addElement(statusDisplay);
	}
 
	protected function commitStatus():void
	{
		if (!statusDisplay)
			return;
		// update the status text to show on the user interface
		statusDisplay.text = status;
	}
}
}

Was All This Code Worth It

Yes, you are looking at a good abstraction of a user interface component that displays a BusyIndicator and Label. This class could be reused, subclassed and skinned. This is the ultimate sunny day for an application developer trust me. Most of the time I see good developers just not wanting to take the time to write good solid component code. This is also where we will get into the eternal fight of unit testing verses refactoring. I guess it comes down to whoever wins the race right? I am confident I will win with the way I write my components, are you confident in your user interface component code (oh you don’t have any reusable components)?

Creating the API

One of the first things I do is break down what is the external (public) communication to this component. Basically we have one thing, the status message. I mentioned in the previous article that the BusyIndicator is basically private meaning locked doors, there is nothing to expose with it. The styles are already there to access with CSS.

Creating the User Interface blocks

The blocks of a component in the Spark framework are skinparts. We know we needed a BusyIndicator, that is busyIndicator skin part. We also know we need a way to express the status text. For simplicity we use the Label that can display single and multiline text. For that we create the statusDisplay skin part.

SkinPart Addition

Here is the controversial part of this article. I am not creating a skin for this component. We actually create the skin parts in the BusyLabelPopUp.

  • We honor the spark skin contract by checking the numElements of the contentGroup so we don’t add composites if they are already there.
  • We create a new vertical layout that will size correctly and center the busyIndicator and statusDisplay.
    • Remember the layout of the SkinnablePopUpContainer is proxied to the contentGroup.
  • We create two hook methods for the creation of the busyIndicator and statusDisplay.
    • This allows for subclass overrides, remember protected in a well designed component is good karma.
  • When creating skinparts in ActionScript, remember to set the id, if you don’t you cannot style them from id selectors in CSS.

Property Commital

Understanding the invalidation passes of a UIComponent is very important. If you get this right, Flex components are very fast. A lot of the times developers curse the Flex framework for it’s bottlenecks in rendering. The sad truth is about 80% of the time it’s those very developers that are creating the bottlenecks with their code.

commitProperties()

The standard property change algorithm is;

  • Check to see if the property has changed.
  • Set a backing variable usually private.
  • Switch a flag that will be picked up in commitProperties()
  • Call invalidateProperties() to trigger commitProperties() on the next frame update.
  • If the property is Bindable, call dispatchEvent(new Event("propertyChanged"))

Once the status property has changed, a frame will pass and commitProperties() will fire. During this method call, if the statusChanged flag is true, commitStatus() will be called and the statusDisplay.text will be updated with the new text.

Note: There is also a pattern where the statusDisplay.text gets called directly in the setter. This has to do with the sync between parent and child. In this example it really dosn’t matter and the commit hook method allows for future adjustment very easily.

PopUp Position And Layout

The layout and position logice we taken out of the view and the SkinnablePopUpContainer has a nice public method that can AND should be overridden; updatePopUpPosition().

In this method we convert the owner‘s point, in the case of the example it’s a View into gloabl coords and apply those x and y values to the popup.

The Updated View Code

<?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="Take2">
 
	<fx:Script>
		<![CDATA[
	import components.BusyLabelPopUp;
 
	private var mTimer:Timer;
 
	private var mPopUp:BusyLabelPopUp;
 
	private var mCount:int = 0;
 
	protected function button1_clickHandler(event:MouseEvent):void
	{
		// if busy, return
		if (mPopUp)
			return;
 
		mCount = 0;
		createPopUp();
		startOperation();
		updateStatus("Loading...");
	}
 
	private function createPopUp():void
	{
		mPopUp = new BusyLabelPopUp();
		mPopUp.open(this);
	}
 
	//--------------------------------------------------------------------------
	// 
	//  Bellow is just Application logic now
	// 
	//--------------------------------------------------------------------------
 
	private function startOperation():void
	{
		mTimer = new Timer(1000);
		mTimer.addEventListener(TimerEvent.TIMER, timerHandler);
		mTimer.start();
	}
 
	private function endOperation():void
	{
		mPopUp.close();
		mPopUp = null;
	}
 
	private function updateStatus(message:String):void
	{
		mPopUp.status = message;
	}
 
	private function timerHandler(event:TimerEvent):void
	{
		updateStatus("Loading... " + mCount++);
 
		if (mCount == 4)
		{
			mTimer.removeEventListener(TimerEvent.TIMER, timerHandler);
			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>

In the code above;

  • Removed all popup logic and layout.
  • Create the BusyLabelPopUp and call open().
  • Create a fake operation that loops 4 times to demonstrate the dynamic status update of the busy overlay.
  • There are only a couple lines of code in the above file that actually have to do with the new component, the rest is application logic.

Styling The PopUp

Now that the PopUp is in a custom component we have gained the ability to control the styles from the outside of ALL skin parts. Here is the application styling that targets our new skinparts of the BusyLabelPopUp component.

@namespace s "library://ns.adobe.com/flex/spark";
@namespace components "components.*";
 
components|BusyLabelPopUp {
	backgroundAlpha:0.3;
	backgroundColor:#000000;
}
 
components|BusyLabelPopUp #busyIndicator {
	symbolColor:#FFFFFF;
	rotationInterval:10;
}
 
components|BusyLabelPopUp #statusDisplay {
	fontWeight:bold;
	color:#FFFFFF;
}

Conclusion

This Take 2 was really a tagent article I took talking about component development. It provided a good example of the two challenges that face application development; Speed verses Reusablity.

If you are developing mobile applications, think about components and what they can do for you. Along that note Teoti Graphix, LLC has a new mobile toolkit coming out and 3 more in the making;

Check out;

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/

Categories: AIR Mobile Tags: ,

Air Mobile :: Hello BusyIndicator take 1

December 5th, 2011 Michael Schmalle No comments

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

create mxml skin

  • With the BusyPopUpSkin.mxml open add the BusyIndicator component to the contentGroup
...
<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 Button was added to the actionContent of the ActionBar to trigger the creation of the popup.
  • A handler was added to create the popup and start the progress operation.
  • The createPopUp() method creates an new SkinnablePopUpContainer and sets it’s skinClass, this is how the skin is applied in this version.
    • The backgroundColor and backgroundAlpha styles are there to show how to adjust the popups background.
  • The layoutPopUp() assigns a new width and height based on the View's width and height.
  • The popup is then opened using the open() method that calls the PopUpManager.
  • The positionPopUp() method takes the View's x, y coords and translates them to global coords so the popup will be placed directly on top of the View.
    • This in effect creates a poor mans modal over the View.
  • The startOperation() method simulates a long running operation that in this case runs three seconds and calls the popups close() 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 View class, 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 BusyLabelPopUp component that subclasses SkinnablePopUpContainer.
    • This will remove all logic from the view.
  • Use the partAdded() method of the new component to add a BusyIndicator and Label component to the contentGroup.
    • 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 status on the new component so real time textual updates are possible through the BusyLabelPopUp public interface.
  • Override the updatePopUpPosition() of the BusyLabelPopUp to 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/

Categories: AIR Mobile Tags: ,

AIR Mobile :: Hello ActionBar take 1

December 2nd, 2011 Michael Schmalle No comments

The ActionBar class defines a component that includes title, navigation, and action content groups. The ActionBar control provides a standard area for navigation and action controls. It lets you define global controls that can be used from anywhere in the application, or controls specific to a view.

What Is The ActionBar

The ActionBar is a SkinnableComponent that contains a titleGroup, navigationGroup and actionGroup. Each of these Groups are populated by using their content properties titleContent, navigationContent and actionContent.

navigationGroup

The navigationGroup provides a consistent placement to the right of the titleGroup for application navigation buttons. When implementing an ActionBar in a mobile application it really comes down to the needs and feel of the application in question. The ActionBar was pretty much born out of a visual design pattern for consistency and user familiratity.

Think of the browser, something most people use almost everyday. This is an ActionBar for the desktop. You have the Back button navigation on the left, the url title in the middle and action items such as search on the right. The navigation items are usually global to the application and sometimes to the View itself.

There are three ways to add items to a navigationGroup;

  • Use the navigationContent Array on the View or ViewNavigator declarativly through MXML.
    • This allows the least flexibility.
  • Use the navigationContent property on the View or ViewNavigator.
    • This allows the View to properly fire property change events and change state.
  • Use ActionScript to add items through the IVisualElementContainer interface.
    • This allows fine grained control of the display list without thinking about what already exists in the navigationContent.
    • Not recomended but possible.

navigationContent MXML Example:

<s:navigationContent>
    <s:Button icon=@Embed(source='/assets/home_icon.png')
              click="dispatchEvent(new Event('homeClick'))"/>
</s:navigationContent>

ActionScript navigationContent Example (inside a View):

// create a new button
var element:Button = new Button();
element.label = "New Button";
// set the new content
navigationContent = [element];

ActionScript display list Example (inside a View):

// get the actionBar from the parent navigator
var actionBar:ActionBar = navigator.actionBar;
// remove all elements from the navigationGroup
actionBar.navigationGroup.removeAllElements();
// create a new button
var element:Button = new Button();
element.label = "New Button";
// ... add handlers etc
// add the button to the navigationGroup
actionBar.navigationGroup.addElement(element);

Note: Using actionscript means you are bypassing the built in mechanism of navigatorContent declarativly to add items from the navigationGroup. This is sometimes needed for dynamically updating the ActionBar's navigation because something about the applications state changed relative to what was initially implemented. Or you are using an application framework with mediators or commands.

titleGroup

The titleGroup is the exception to the above rule when using the ActionBar‘s content properties. The ActionBar title property when set creates a titleDisplay that is placed inside the titleGroup created in the ActionBarSkin. When a title String is not set on the ActionBar or parent IViewNavigator, the titleGroup is still created. The default titleDisplay component the skin creates is an internal TitleDisplayComponent that wraps two StyleableTextField components to create a title shadow effect.

You may be wondering why the titleDisplay is created when you can set the titleContent of the ActionBar. The above functionality allows for a default implemetation of the title property. Instead of having to put a Label inside the titleGroup every time you use the ActionBar, by default the title will be placed in the titleDisplay created in ActionBarSkin.createChildren().

Style the titleDisplay

s|ActionBar #titleDisplay {
	color:#F7F7F7;
	textShadowAlpha:1;
}

Note: To use a TypeSelector such as s|ActionBar, you must define these from within the main application’s css or external css file.

actionGroup

The actionGroup provides a consistent placement to the full right that define actions the user can take in a view. As mentioned witht the navagationGroup, the actionGroup will contain items such as a search button or even an overflow action menu.

The actionGroup uses the same pattern for population as the navigationGroup(see above). The actionContent Array will be used to assign controls to the actionGroup instance.

Layouts

The navigationGroup and actionGroup also have sibling properties in navigationLayout and actionLayout. These added properties allow the developer to target specific padding, gaps and alignment for each group. Not adding these proxied properties in the ActionBar would mean you would have to set a new Group for each content if you wanted to change any of the charateristics of their layouts.

What Is The ActionBar Used For

The ActionBar is used for a consistent placement of title, navigation and actions. The component also very closely follows the existing ActionBar user interface pattern defined by most mobile OSs and browsers.

What Is The ActionBarSkin

The ActionBarSkin is an actionscript class that creates the ActionBar‘s skin parts, border and paints the background gradient.

SkinParts

  • navigationGroup:Group – defines the appearance of the navigation area of the component.
  • titleGroup:Group – defines the appearance of the title area of the component.
  • titleDisplay:IDisplayText – defines the appearance of the title text in the component.
  • actionGroup:Group – defines the appearance of the action area of the component.

Styles

How to style the default ActionBarSkin;

  • Use the chormeColor style to set the backgrounds gradient color.
  • Use the backgroundAlpha style to set the background gradient transparency.
  • Use the padding styles to offset all content Groups.
s|ActionBar {
	chromeColor:#3399FF;
	backgroundAlpha:0.4;
}

Custom skin

To illustrate how to skin these archaic mobile skins lets say we want our own gradient and botom border.

package skins
{
 
import flash.display.GradientType;
import flash.geom.Matrix;
 
import spark.skins.mobile.ActionBarSkin;
 
public class MyActionBarSkin extends ActionBarSkin
{
	private static var colorMatrix:Matrix = new Matrix();
 
	private var mFillColors:Array = [0xCCCCCC, 0xFFFFFF, 0xBCBCBC];
	private var mFillAlphas:Array = [1, 1, 1];
	private var mFillRatios:Array = [0, 50, 255];
	private var mLineColor:uint = 0x333333;
	private var mLineWeight:int = 2;
 
	public function MyActionBarSkin()
	{
		super();
 
		borderClass = null;
	}
 
	override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
	{
		var fillColors:Array = (getStyle("actionBarColors") == null) ? mFillColors : getStyle("actionBarColors");
		var fillAlphas:Array = (getStyle("actionBarAlphas") == null) ? mFillAlphas : getStyle("actionBarAlphas");
		var fillRatios:Array = (getStyle("actionBarRatios") == null) ? mFillRatios : getStyle("actionBarRatios");
 
		var lineColor:uint = (isNaN(getStyle("lineColor"))) ? mLineColor : getStyle("lineColor");
		var lineWeight:int = (isNaN(getStyle("lineWeight"))) ? mLineWeight : getStyle("lineWeight");
 
		colorMatrix.createGradientBox(unscaledWidth, unscaledHeight, Math.PI / 2, 0, 0);
 
		graphics.beginGradientFill(GradientType.LINEAR, fillColors, fillAlphas, fillRatios, colorMatrix);
		graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
		graphics.endFill();
 
		graphics.beginFill(lineColor, 1);
		graphics.drawRect(0, unscaledHeight - lineWeight, unscaledWidth, lineWeight);
		graphics.endFill();
	}
}
}

Whats going on in that code?

  • Create a new MyActionBarSkin based off of the ActionBarSkin
  • Create a constructor that nulls out the border shadow (FXG)
  • Override the drawBackground() method to disabled ActionBarSkin from painting it’s background gradient based of chromeColor
  • Make up some new styles for our implementation so we can change things from the outside with CSS
    • actionBarColors, actionBarAlphas, actionBarRatios, lineColor, lineWeight
  • Create a Matrix box for gradient painting
  • Use Graphics.beginGradientFill() to paint the custom background gradient
  • Use Graphics.drawRect() to paint the bottom border line

Implementing the new skin

CSS code

s|ActionBar s|Button {
	color:#333333;
	textShadowAlpha:0;
}
 
s|ActionBar #titleDisplay {
	color:#333333;
	textShadowAlpha:0;
}
 
s|ActionBar {
	skinClass:ClassReference("skins.MyActionBarSkin");
	chromeColor:#BEBEBE;
	paddingTop:0;
	paddingBottom:0;
	/* add the new styles to override the base styles set in the skin*/
}

The message in the example is, with a little code, you can create vast amounts of reusable skins that are styled with your own custom CSS. Adobe purposly made skins basically styleless because there are somany different use cases out there. They leave it up to the developer to choose between FXG, Bitmaps or the programmatic approach with draws fast and is reusable.

Notes:

  • Setting defaults in the code is a good way to make your skin work out of the box.
  • getStyle() is NOT an expensive method call, setStyle() is expensive.
  • Making the default mutable style properties in the skin subclass protected allows the the developer to choose between actionscript and CSS. Properties can be updated in a subclass by setting them in the constructor without having to reimplement the drawing logic of the superclass.
  • The above class is simple and is not applying DPI resolution adjustments.
    • Note that this could be done using media quires in CSS adjusting the lineWeight style

What Are The ActionBar States

The ActionBar state;

  • titletitle with no actionContent or navigationContent
  • titleWithAction -titlewith actionContent and no navigationContent
  • titleWithNavigation -titlewith navigationContent and no actionContent
  • titleWithActionAndNavigation -titlewith navigationContent and actionContent
  • titleContenttitleContent with no title, actionContent or navigationContent
  • titleContentWithActiontitleContent with actionContent and no title or navigationContent
  • titleContentWithNavigationtitleContent with navigationContentand no title or actionContent
  • titleContentWithActionAndNavigation - titleContent with actionContent and navigationContent and no title

Conclusion

The ActionBar is a very usefull component based on established user interface design patterns. The key to using the ActionBar is understanding how it fits into the ViewNavigatorApplication and View. The ActionBar can also be used as a stand alone component in a regualr spark Application. Using the component in this manner requires the developer to wire everything up. The former, Adobe has already done some heavy lifting for the developer.

I will be writting more in depth about the ActionBar when the series progresses to ViewNavigators.

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/

Categories: AIR Mobile Tags: ,

AIR Mobile :: Hello Flex 4.6 – MobileUIToolkit1

December 1st, 2011 Michael Schmalle 4 comments

Hi,

Well things in the last month have been pretty fun, from the depths of the abyss back to a release of the Flex SDK that Adobe wants you to believe in. Hello Flex SDK and Flash Builder 4.6.

I’m not going to go into my opinion of what has gone on with the Flash is Dead popcorn that has been floating around the internet because it really doesn’t matter to me. What do I mean; Well having been with the Flash Player since it’s itty bitty version 5 (2002), I can’t abandon ship yet. There are those that stay and can repair the damage done by the drunk captain (In this case Adobe).

I really don’t think AIR for mobile is going away in the near future and that is what I have put my time into. I’m no stranger to Java and Android, which I love. I have re-consolidated my eggs based on the damage done by Adobe but I am still here ready to help those that see the true power in AIR for mobile cross platform applications.

Teoti Graphix, LLC is here to offer a new mobile component toolkit. I’m ironing out the creases and finishing up the documentation but, next week I will release our first mobile toolkit MobileUIToolkit1.

The Components

  • PopUp – A self contained class that acts much like Android’s Toast with duration layout placement and more.
  • Dialog – The base for all dialogs used with the PopUp.
  • AlertDialog – A modal or non modal dialog that uses events and implements a button provider for it’s control buttons.
  • TextDialog – A dialog that uses a custom text content renderer (this is the default PopUp dialog).
  • ProgressBar – A progress bar that implements primary, secondary and indeterminate values with optional direction switching. As well as many styles to adjust the look through CSS.
  • MobileButton – A simple implementation of a spark Button that includes a longClick event and longClickDelay style.
  • Picker – A simple increment – decrement picker with dataProvider and data cycling.
  • RatingBar – The cliche mobile component that everybody needs. The component is based off of the ProgressBar which gives it even more power and usability. The RatingBar is touch-drag enabled.
  • WebView – A simple UIComponent implementation of the StageWebView. Note this is an "extra" and may not work in some mobile application designs due to the native nature of the StageWebView.

The component kit offers time saving unit tested code with over 8 years of Flash Player component development. All of our components are tested and documented at the professional level a mobile application developer can feel confident in using.

Check out the documentation of the PopUp class;

PopUp class Reference

All of our component kits come with support response time within 24 hours excluding weekends and holidays. You can google our company and see we have been on the front lines helping the Flex/AIR community since Flex version 2.

All of our mobile component skins are optimized in ActionScript and some have secondary MXML skins for those that want them. Skins are also DPI aware and will adjust according to the Application’s DPI.

The above being said, I had the pleasure of participating in the 4.6 pre-release program and have put together a large Hello World style blog article series for all of the Flex 4.6 mobile components. Stay tuned, I will start posting these next week.

Why buy from Teoti Graphix, LLC: We have been doing this longer than anybody creating custom flash/flex components and we are not going anywhere, just look us up. Unit tests? Who needs them, you do and have the ability to purchase them as well with all the source code.

Again; If you want to see pretty images and professional documentation visit;

PopUp class Reference

Some images of our new toolkit; (Every component can be skinned and styled)

AlertDialog

Picker

Text PopUp

Icon Text PopUp

ProgressBar

ProgressBar

RatingBar

More to come;

Mike

AIR3 :: FREObject and using accessors on AS3 class

October 7th, 2011 Michael Schmalle 4 comments

Hi,

UPDATE: Seeing as I have applied for the FlashBuilder 4.6 preview and not heard back yet, I am flying by the seat of my pants. I think I got this issue solved(not passing null for the FREObject.newObject() call), it must have been an exception getting swallowed somewhere because I have pushed ahead farther and backtracked to this problem. Things work, I hate sounding like an idiot below but hey this is bleeding edge development.

The Problem Solved:Now that I think about it, the call to FREObject.newObject() created a String and then the actual Exception came from the code trying to set “test” on the String class which we know does not exists.

I think this method signature might bite a couple devs in the ass once or twice. :)

I have been scowering the scant documentation on the FREObject class and most of it is copy and paste everywhere. I’m at about 4 hours of serious determination when I am slowly realizing either I am doing something wrong or using an ActionScript class’s accessors just don’t work in the just released Java API for AIR native extensions.

I can successfully set a public var, call a method but when I try to set a setter property, I get an com.adobe.fre.FRENoSuchNameException.

AS3 class:

package com.teotigraphix.android.foo {
public class Bar {
    public var baz:int;
    private var _test:String;
    public function get test():String{
         return _test;
    }
    public function set test(value:String):void {
         _test = value;
    }
    public function Bar() {
    }
}
}

Works:

FREObject instance = FREObject.newObject("com.teotigraphix.android.foo.Bar");
instance.setProperty("baz", FREObject.newObject(42));

Doesn’t work:

Throws com.adobe.fre.FRENoSuchNameException.

FREObject instance = FREObject.newObject("com.teotigraphix.android.foo.Bar",);
instance.setProperty("test", FREObject.newObject("42"));

Does anybody out there have an idea or have seen this before? Maybe a bug?

Mike

FlashBuilder 4.5 :: Getting FlexUnit to work with Mobile components

October 3rd, 2011 Michael Schmalle 5 comments

Hi,

Maybe I missed this in the plethora of documentation of FlashBuilder 4.5, maybe it’s coming in the next free update but when I tried to run FlexUnit in the Flex Mobile Project, the IDE said FlexUnit is not supported in this version.

Well, I need to test mobile user interface components for my next product set, how do I get this to work? Going back to a previous problem I had with Flex Library projects rejecting the existence of the mobile skins theme I realized this must be the same problem in a way.

Side Note:

If you want to create a Flex Library project using Mobile skins say creating component skin that subclass MobileSkn, you need to add the theme SWC to the build path.

  1. Right Click on the library project.
  2. Select Properties
  3. Select Library Build Path
  4. Select the Library path tab
  5. Click Add SWC…
  6. Browse to the folder approximately in C:\Program Files (x86)\Adobe\Adobe Flash Builder 4.5\sdks\4.5.1\frameworks\themes\Mobile\mobile.swc
  7. Select the newly added swc in the Build path libraries:
  8. Expand the selection
  9. Double click on the Link Type:
  10. Select External from the Link Type: dropdown
  11. Click OK
  12. Click OK

Now your Library project is a Flex Mobile Library project. I am sure they will have this fixed in the next update.

Getting back to FlexUnit

What I ended up doing was adding the two mobile SWCs to the build path. This is using a Flex Project with AIR deps.

  1. Right Click on the Mobile project.
  2. Select Properties
  3. Select Flex Build Path
  4. Select the Library path tab
  5. Click Add SWC…
  6. Browse to the folder approximately in C:\Program Files (x86)\Adobe\Adobe Flash Builder 4.5\sdks\4.5.1\frameworks\themes\Mobile\mobile.swc
  7. C:\Program Files (x86)\Adobe\Adobe Flash Builder 4.5\sdks\4.5.1\frameworks\libs\mobile\mobilecomponents.swc

Now the project contains the necessary SWCs to create FlexUnit tests. What I ended up doing is since I am creating mobile ui components, I just included my Mobile Library project in the build path of the FlexUnit test application.

I have successfully unit test all my mobile user interface components using this project and the FlexUnit test runner.

Peace,
Mike

Categories: Uncategorized Tags:

Spark :: Skinnable Navigator library :: Open Source

September 29th, 2011 Michael Schmalle 4 comments

Hello,

It’s been since July since I have posted anything, that was due to the fact I have been working on some very large AIR projects, polishing up asblocks(ActionScript3 DOM parser framework) and another OpneSource AIR application that should be of interest to a lot of AS3 programmers that hate writing ASDoc documentation.

I know from google analytics there have been a lot of interest in Spark navigators, yes the skinnable kind. I wrote a blog post about a year or so ago called Spark navigators :: ViewStack – TabNavigator – Accordion. Read the post if you want images or more information.

Basically, I have decided to open source it because I am using it in a lot of my open source projects. The TabNavigator works great, one thing that is missing I think is proper keyboard support but that is on the list.

The libraries features to date include;

Components

  • ViewStack
  • TabNavigator
  • TabBar
  • TabButton
  • Accordion, AccordionHeader

Skins

  • ViewStackSkin
  • TabNavigatorSkin
  • TabBarSkin, TabTopSkin, TabBottomSkin, TabLeftSkin, TabRightSkin
  • AccordionSkin, AccordionHeaderSkin
  • SimpleBorderSkin

Layouts

  • ViewStackLayout
  • TabNavigatorSkinLayout
  • HorizontalButtonBarLayout
  • VerticalButtonBarLayout
  • AccordionSkinLayout
  • AccordionSkinLayoutAnimated

Major Features:

  • Skinnable TabNavigator
  • Multi-state close button functionality
  • Cancelable CLOSE Event
  • Top, right, bottom and left tabbar placement

Source Code:

GitHub ui.navigator library

Any bug finds appreciated, there is still much to do and consider this a beta release. I have not yet refactored and asdoced properly yet.

Mike

AS3 :: ASBlocks :: Java impl IStatementContainer example

July 29th, 2011 Michael Schmalle 6 comments

Hi,

Just wanted to show you where the Java impl DOM is at for jas-blocks (Java ActionScript Blocks). This framework reads and writes ActionScript3 from Java applications.

The Java source code to create the output below;

ASBlocks Wiki Labs for a bunch of documentation. I am always adding to this as I get deeper into this framework.

Feel free to ask any questions or let me know if you are interested in some near future beta testing.

public static void createClassStatements(IASProject project)
{
	IASCompilationUnit unit = project.newClass("foo.bar.ClassStatements");
 
	IASPackage pckg = (IASPackage) unit.getPackage();
	IASClassType ctype = (IASClassType) unit.getType();
	IASMethod method = ctype.newMethod("statements", Visibility.PUBLIC, "void");
 
	// IASBreakStatement
	IASBreakStatement bs = method.newBreak();
	bs = method.newBreak("foo");
 
	// IASConfigStatement
	IASConfigStatement config = method.newConfig(factory.newExpression("debug"));
	config.addComment(" debug configuration");
 
	// IASContinueStatement
	IASContinueStatement cs = method.newContinue();
	cs = method.newContinue("bar");
 
	//TODO IASDeclarationStatement
	IASDeclarationStatement ds = method.newDeclaration(factory.newExpression("i:int = 0"));
 
	// IASDefaultXMLNamespaceStatement
	IASDefaultXMLNamespaceStatement dns = method.newDefaultXMLNamespace("http://foo.bar");
 
	// IASDoWhileStatement
	IASDoWhileStatement dws = method.newDoWhile(factory.newExpression("a < b"));
	dws.addComment(" do while()");
 
	// IASExpressionStatement
	IASExpressionStatement es = method.newExpressionStatement(factory.newExpression("trace('expression statement')"));
 
	// IASForStatement
	IASForStatement fs = method.newFor(null, null, null);
	fs.addComment(" for statement uninitialized");
	fs = method.newFor(factory.newDeclaration("i:int = 0"), factory.newExpression("i < len"), factory.newExpression("i++"));
	fs.addComment(" for statement initialized");
 
	// IASForEachInStatement
	IASForEachInStatement fei = method.newForEachIn(factory.newDeclaration("obj:Object"), factory.newExpression("obj[foo]"));
	fei.addComment(" for each in statement");
 
	// IASForInStatement
	IASForInStatement fi = method.newForIn(factory.newDeclaration("obj:Object"), factory.newExpression("obj[foo][0]"));
	fi.addComment(" for in statement");
 
	// IASIfStatement
	IASIfStatement ifs = method.newIf(factory.newExpression("!foo"));
	ifs.addComment(" if statement");
	ifs.getElse().addComment("else statement");
 
	// IASLabelStatement
	IASLabelStatement ls = method.newLabel(factory.newExpression("foo"));
	ls = method.newLabel(factory.newExpression("bar"));
	//TODO figure out the api for this
	IASDoWhileStatement lsl = new ASTASDoWhileStatement(ASTStatementBuilder.newDoWhileAST("true"));
	ls.setStatement(lsl);
 
	// IASReturnStatement
	IASReturnStatement rs = method.newReturn();
	rs = method.newReturn(factory.newExpression("foo()"));
 
	// IASSuperStatement
	// NA
 
	// IASSwitchStatement
	IASSwitchStatement ss = method.newSwitch(factory.newExpression("foo.bar"));
	IASSwitchCase swc = ss.newCase("1");
	swc.addComment(" switch case 1");
	IASSwitchDefault swd = ss.newDefault();
	swd.addComment(" switch default");
 
	// IASThrowStatement
	IASThrowStatement ts = method.newThrow(factory.newExpression("new Error('throw me')"));
	ts = method.newThrow(factory.newExpression("other.error(e)"));
 
	// IASTryStatement
	IASTryStatement trs = method.newTryCatch("e", "Error");
	trs.addComment(" the try block");
	trs.getCatchClauses().get(0).addComment(" the catch block");
	IASFinallyClause fic = trs.newFinallyClause();
	fic.addComment(" the finally clause");
 
	trs = method.newTryFinally();
	trs.addComment(" the try block");
	trs.getFinallyClause().addComment(" the finally block");
	trs.newCatchClause("e1", "Error").addComment(" the catch clause");
 
	// IASWhileStatement
	IASWhileStatement ws = method.newWhile(factory.newExpression("a < b"));
	ws.addComment(" while statement block");
 
	// IASWithStatement
	IASWithStatement wts = method.newWith(factory.newExpression("foo.bar"));
	wts.addComment(" with statement body");
}

ActionScript3 output

package foo.bar {
	public class ClassStatements {
		public function statements():void {
			break;
			break foo;
			CONFIG::debug {
				// debug configuration
			}
			continue;
			continue bar;
			var i;
			default xml namespace = "http://foo.bar";
			do {
				// do while()
			} while (a < b);
			trace('expression statement');
			for (; ; ) {
				// for statement uninitialized
			}
			for (var i:int = 0; i < len; i++) {
				// for statement initialized
			}
			for each(var obj:Object in obj[foo]) {
				// for each in statement
			}
			for (var obj:Object in obj[foo][0]) {
				// for in statement
			}
			if (!foo) {
				// if statement
			} else {
				//else statement
			}
			foo: {
			}
			bar: do {
			} while (true);
			return;
			return foo();
			switch (foo.bar) {
				case 1:
					// switch case 1
				default:
					// switch default
			}
			throw new Error('throw me');
			throw other.error(e);
			try {
				// the try block
			} catch (e:Error) {
				// the catch block
			} finally {
				// the finally clause
			}
			try {
				// the try block
			} catch (e1:Error) {
				// the catch clause
			} finally {
				// the finally block
			}
			while (a < b) {
				// while statement block
			}
			with (foo.bar) {
				// with statement body
			}
		}
	}
}

Remember, this is one VERY SMALL piece of the jas-blocks DOM. We are only talking statement container here.

I’m getting so close to an alpha release but, I have been in the business long enough to know I don’t want to put anything out there until I am sure of the DOM.

ASBlocks Wiki Labs for a bunch of documentation. I am always adding to this as I get deeper into this framework.

PS, I have the framework parsing MXML now to! I am releasing an FX Dom under com.teotigraphix.fxblocks. The as3 is all released under the org.as3commons.asblocks package.

Peace,
Mike

AS3 :: ASBlocks :: ActionsScript and Java Dom impls

July 12th, 2011 Michael Schmalle 2 comments

Hi,

EDIT :: This post says that the AST is not adding the second child (IDENT), the parser still parses the UIComponent.as class. ;-) So you can still parse and file right now, just not have access to the recursive field identifiers, the field access nodes are there (the idents parent)

The last two weeks I have been cramming an ANTLR3 AS3.g file for both ActionScript3 and Java implementations. Refactor after refactor bug, learning, all the above going on. Today, I commented the 2000 line grammar, indented all pretty like, sectioned rules logically and thought ok, it’s time mirror over the ActionScript version again.

Since this was a pretty feature complete grammar for the as3 impl (alpha), I was working in Java since the unit testing went about 5 times faster. I have 2000 lines of unit tests (70 tests) for the AS3Parser rules. I have abstracted them so I basically can just copy and paste the Java tests into ActionScript tests.

Ok, this is great, I’m all ready to fire up the ActionScript test suite, now I hit run, flex unit does it’s thing I think I’m going to get all GREEN, WRONG! There were two tests that failed!

This is bad because the two tests that failed have to do with recursive postfix field access and array access. There is something screwy going on with the recursive rewrite rules in the ActionScript version. So now, I have to get some answers on what is going wrong.

The point of this sad story is I am getting so close to an alpha release a for ActionScript (the DOM is implemented Expressions included). So this is a set back for the parsing end. Although for the creation end, say creating field and array access expression through API such as;

var target:IASExpression = factory.newExpression("myObject[42]");
var subscript:IASExpression = factory.newExpression("0");
var aae:IASArrayAccessExpression = factory.newArrayAccessExpression(target, subscript);
// or
var target:IASExpression = factory.newExpression("foo()");
var name:String = "bar";
var fa:IASFieldAccessExpression = factory.newFieldAccessExpression(target, name);

the above is still possible recursively since I use an ASTBuilder not the parser.

The Plan

I will tidy the ActionScript version up, get it ready for an alpha release with this bug included. I am going to spend a large amount of time on the Java branch now. I have this branch implemented to the statement.

Anyway I know there are a lot interested in this project, hold on tight, code is on the way.

The good news is I have the AS3.g somewhat stable, that was an insane trip.

Mike

AS3 :: ASBlocks :: ASDoc parser comes along aswell!

July 5th, 2011 Michael Schmalle 2 comments

Hi,

Just wanted to pass along the fact that along with this great AS3Parser and as3 DOM, there is an antlr parser with linked token implementation and DOM as well.

This means that creating, editing and moving asdoc comments around in an Adobe AIR application could never be easier.

Core Example using the actual parser (not DOM)

private static function parse(str:String):LinkedListTree
{
	var parser:ASDocParser = parserOn(str);
	return parser.comment_body().tree as LinkedListTree;
}
 
private static function parserOn(str:String):ASDocParser
{
	var cs:ANTLRStringStream = new ANTLRStringStream(str);
	var lexer:ASDocLexer = new ASDocLexer(cs);
 
	var linker:LinkedListTokenSource = new LinkedListTokenSource(lexer);
	var stream:LinkedListTokenStream = new LinkedListTokenStream(linker);
 
	var parser:ASDocParser = new ASDocParser(stream);
	parser.treeAdaptor = TREE_ADAPTOR;
 
	//parser.setInput(lexer, cs);
	return parser;
}
 
// impl
 
var body:LinkedListTree = parse("/** Hello world! @author Mike Schmalle */);

The underlying tokens and AST is pure ANTLR API, so there is huge flexibility at traversing and inspecting the AST tree. The use of the linked token list allows for token traversing as well.

The ASBlocks project is aimed to bring a new level of Pure Actionscript/Flex tool applications into existence. I have been working on this project for over 3 years in various stages.

I have heard rumors of some that want to try and use this framework as an ActionScript compiler, we will see.

Stay tuned, I’m getting real close to getting this new branch up online in GIT so you can start experimenting.

Mike

Categories: Uncategorized Tags: ,