How to use the AS3-Layout-Framework
November 9th, 2008 • AS3-Layout-Framework, Actionscript 3.0, Design Patterns
The AS3-Layout-Framework is basically very simple and easy to understand. It is based on one structural (Composite) and one behavioural (Strategy) pattern.
The composite pattern is used to compose objects into tree structures to represent part-whole hierarchies. Also it has the advantage to let clients treat individual objects and compositions of objects uniformly[GHJV95]. While updating all ILayoutComponents, a ILayoutContainer ( extends ILayoutComponent) lays out its subcomponents and a simple ILayoutComponent just handles its bounds ( Figure 1 shows the inheritance structure of the participants in more detail ).
The strategy pattern is used to encapsulate algorithms in objects with a well formed interface and lets the algorithm vary independently from clients that use it[GHJV95].
In the AS3-Layout-Framework the ILayout embodied the strategy pattern. This makes the creation of concrete layouts very simple and easy to plug in (f.e. GridLayout, FlowLayout).
Display representation:
The AS3-Layout-Framework itself is loosely-coupled from the display list. But to ease the use of it in daily usage, UILayoutComponent extends Sprite and according to that UILayoutComponent and UILayoutContainer are binded to the display list ( see the inheritance structure in Figure 1 ).
To layout an existing project all visible representations just have to extend UILayoutComponent or UILayoutContainer.
In addition ILayoutComponent extends ILayoutObservable and provides the functionality to add ILayoutObservers. Which means that other objects can register themself for specific layout events.
NOTE: The fact that ECMA-Script does not support multiple inheritance led to simplify the display inheritance structure. Otherwise the existing code had to be copied in every new concrete implementation (Bitmap, Shape, Sprite, MovieClip...). This would end up in error prone and unmaintainable code.
Worth knowing:
The internal data structure of the AS3-Layout-Framework is very similar to the data structure of the IList interface in the AS3-Collection-Framework.
This means that the add, remove and set methods work nearly the same way. There is just one difference: there are no null s allowed. After adding a ILayoutComponent at a specified index bigger than the component amount, the lag will be filled with NullComponent s. This has one big advantage. Developers can customize there own ILayoutStrategy without dealing with lags in calculation.
The following section covers two fundamental use cases of the layout's data structure, which is especially for those readers who are not familiar with the AS3-Collection-Framework.
addComponentAt( index: int, c: ILayoutComponent ): void
- adds a
ILayoutComponent at a specified index, if the index is bigger than the component amount, the lag will be filled with NullComponent s (list does not contain null s), otherwise the element currently at that position and any subsequent elements will be shifted to the right and the given ILayoutComponent will be inserted at the specified index.NOTE: same as
splice( index, 0, object ) in the Array class.setComponentAt( index: int, c: ILayoutComponent ): void
- sets a
ILayoutComponent at a specified index, if the index is bigger than the component amount, the same logic of addComponentAt( index: int, c: ILayoutComponent ) takes place. Otherwise the ILayoutComponent at the specified index will be replaced with the given ILayoutComponent.NOTE: same as
splice( index, 1, object ) in the Array classExample:
SimpleLayoutExample.as
package { import com.addicted2flash.layout.Column; import com.addicted2flash.layout.FlowLayout; import com.addicted2flash.layout.GridLayout; import com.addicted2flash.layout.ILayoutStrategy; import com.addicted2flash.layout.LayoutMatrix; import com.addicted2flash.layout.LayoutSettings; import com.addicted2flash.layout.Padding; import com.addicted2flash.layout.Row; import com.addicted2flash.layout.Size; import com.addicted2flash.layout.Style; import com.addicted2flash.layout.UILayoutContainer; import com.addicted2flash.layout.example.SimpleComponent; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.geom.Rectangle; /** * @author Tim Richter */ public class SimpleLayoutExample extends Sprite { protected var _container: UILayoutContainer; /** * Create a new <code>SimpleLayoutExample</code>. */ public function SimpleLayoutExample() { stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.addEventListener( Event.RESIZE, onResize ); _container = new UILayoutContainer( new LayoutSettings( 0, 0, new Size( 800, 600 ) ) ); addChild( _container ); // _container.layout = createFlowLayout(); _container.layout = createGridLayout(); _container.padding = new Padding( 10, 5, 25, 50 ); _container.addComponent( new SimpleComponent( new LayoutSettings( .5, .5, new Size( 100, 80 ) ) ) ); _container.addComponent( new SimpleComponent( new LayoutSettings( 0, 1, new Size( 140, 100 ) ) ) ); _container.addComponent( new SimpleComponent( ) ); _container.addComponent( new SimpleComponent( ) ); _container.addComponent( new SimpleComponent( ) ); update( ); } /** * @inheritDoc */ protected function update(): void { _container.setLayoutSize( stage.stageWidth, stage.stageHeight ); } protected function createFlowLayout(): ILayoutStrategy { return new FlowLayout( 0, 0, Style.BOTTOM_RIGHT ); } protected function createGridLayout(): ILayoutStrategy { return new GridLayout( 3, 4, 10, 20, Style.RIGHT_TO_LEFT ); } private function onResize( event: Event ): void { update(); } } }
SimpleComponent.as
package { import com.addicted2flash.layout.ILayoutComponent; import com.addicted2flash.layout.LayoutEventType; import com.addicted2flash.layout.LayoutSettings; import com.addicted2flash.layout.UILayoutComponent; import flash.geom.Rectangle; import flash.text.TextField; import flash.text.TextFieldAutoSize; /** * This class represents a basic <code>UILayoutComponent</code> that draws an outline around * the layout bounds. * * @author Tim Richter */ public class SimpleComponent extends UILayoutComponent { private static var _count: int = 0; private var _tField: TextField; /** * Create a new <code>SimpleComponent</code>. * * @param settings <code>LayoutSettings</code> */ public function SimpleComponent( settings: LayoutSettings = null ) { super( settings ); initialize( ); } /** * @inheritDoc */ override public function processLayoutEvent( type: int, c: ILayoutComponent ): void { if( type & LayoutEventType.BOUNDS ) { drawOutline( layoutBounds ); updateTextField( ); } } private function updateTextField(): void { _tField.x = ( layoutBounds.width - _tField.textWidth ) / 2; _tField.y = ( layoutBounds.height - _tField.textHeight ) / 2; } private function drawOutline( bounds: Rectangle ): void { graphics.clear( ); graphics.lineStyle( 1, 0xcecece ); graphics.beginFill( 0xdddddd, .4 ); graphics.drawRect( 0, 0, bounds.width, bounds.height ); } private function initialize(): void { _tField = new TextField( ); _tField.textColor = 0x666666; _tField.autoSize = TextFieldAutoSize.LEFT; _tField.selectable = false; _tField.text = ( _count++ ).toString(); addChild( _tField ); } } }

Figure 1 : Inheritance structure of AS3-Layout-Framework
References:
[GHJV95] E. Gamma, R. Helm, R. Johnson, and J. Vlissides, Design Patterns – Elements of Reusable Object-Oriented Software, Addison-Wesley, 1995
11 Responses (Add Your Comment)
-
-
Thanks for your reply… I look forward to looking furthur into the framework and sharing my results with you.
I noticed that you mentioned that it doesn’t make sense not to resize the container if the stage is less than the minimum size of the container. I think I understand what you mean concerning the workflow and I guess I will have to agree. What I was referring to was this:
With an HTML div layout you can create a container div with child divs in it which resize according to the browser “stage” but when the browser is smaller than the minimum height or width (set in CSS) of that parent container… the container no longer resizes.
For the moment I’ll make do
Thanks for the great framework. -
Franck December 12, 2008at 09:38
Hello,
In the current example, and also in the GridLayout and the FlowLayout examples you write:
_container = new UILayoutContainer(…
// …
_container.updateLayoutComponent(…But I can’t find any updateLayoutComponent method in the UILayoutContainer class.
So I always have errors when I compile your examples.
I browse an old revision of this class (16 nov revision here: http://code.google.com/p/addicted2flash/source/browse/trunk/src/com/addicted2flash/layout/UILayoutComponent.as?r=205) and I can’t find this method.
The SimpleComponent.as fire also a compilation error : “1020: Method marked override must override another method.”
I would love to test your framework because it seems that yours is the most developed that can be found in opensource. It would be great if you could post your examples with sources (.as + FLA) ready to compile.
-
Franck December 13, 2008at 11:21
Hello again,
I try the new files and it works. Thank you!
Just to note, the as code on the page is still wrong
I try to compile the GridLayout example (http://www.addicted2flash.com/2008/11/the-gridlayout/) and the FlowLayout example (http://www.addicted2flash.com/2008/11/the-flowlayout/) and I still have multiple errors on each. Can you correct those too please ?
-
Franck December 15, 2008at 08:08
Hello again,
I just trying to use the LayoutDebugger class.Just to note, the example at the top of the asdoc file (http://www.addicted2flash.com/api/com/addicted2flash/layout/LayoutDebugger.html or http://code.google.com/p/addicted2flash/source/browse/trunk/src/com/addicted2flash/layout/LayoutDebugger.as) is wrong.
LayoutDebugger.initialize can’t take LayoutDebuggerSettings as parameter. And it’s missing some “)” brackets.
-
Franck December 15, 2008at 23:03
Yes if works now. All 4 examples (flow, grid,…) Thanks!
About the Debbuger. It seems impossible to render the Row or the Column with the debbuger. Can you confirm it ?
Hi! I have just come across your layout framework! It works wonders! The example code is a bit confusing because the LEFT_TO_RIGHT and TOP_TO_BOTTOM lines cause errors but I just removed these!
However, I was just wondering how I might go about setting minimum width and height for the container. What I mean is that if the stage size is less than a given height or width then the layout should not resize.
Also, is it possible to update the layout at run time: i.e. to add or remove columns or rows from a configuration panel I am considering to create.
And is it possible to create columns and rows inside an existing column or row?
I know I am asking a lot of questions but if you have time to answer them I will be very grateful and will gladly share any modifications I might have made for a layout configuration at run time