BaseUI v3 layout manager
Posted by: Romuald in BaseUI, tags: as3, BaseUI, class, flash, liquid layout, liquid UI, tutorialHi everyone,
Before going on holiday, here is a BaseUI major release
Demo, source and code are at the end of the post or in the BaseUI main Page.
It means code written for the previous might not work for this version (even is there isn’t any major change in the structure, some internal code has been changed). If you want to update your code with this version, unless you were using the version 1, it won’t take a long time to adapt it.
I won’t explain in details the basics of BaseUI, you’ll find complete explanations in the tutorials in the BaseUI main page.
Before we could say that BaseUI was an assets manager, now it is becoming a real layout manager.
The two main classes BaseUI and ElementUI allow you to handle assets positioning by using properties on your DisplayObject like top, bottom, width, percentage width, horizontal center and so on, to make them working with the resize event (when the browser is resized by the user). It makes you able to handle liquid layouts, but also works with fixed layouts.
In the first version, BaseUI has been built mainly to work on the stage. It is working now from the version 2 with any reference, stage or another DisplayObject (see properties like onstage and reference).
As I’m also a Flex user and I’ve started to build layout for Flash taking example of the Flex framework.
In this version you’ll find a canvas, a horizontal box, a vertical box and a tile. Those new classes will be found in a layout package: CanvasUI, HBoxUI, VBoxUI and TileUI. All kind of components you can find in the Flex framework, even the name is very close so you don’t get lost with alien class name. Let’s keep things simple.
Before we start on the new classes, let’s see what the changes in BaseUI and ElementUI are. Well, almost nothing changed in appearance. Bugs have been solved and few methods and properties added.
BaseUI
Method: contains
Return true of false if the BaseUI instance already contains the DisplayObject, like you can find in a DisplayObjectContainer such as Sprite or MovieClip.
Property: autoRefresh (default true)
This is a global setting, meaning all the ElementUI created by adding DisplayObject to the BaseUI instance will get the same setting, it can be overridden in each ElementUI instance. By default, when you set a property on an ElementUI instance, the size and positions of the DisplayObject are automatically calculated and “refreshed”. Using autoRefresh set to false, you’ll have to refresh yourself the element by using the refresh methods. This applies only for setting properties, the elements will still be automatically “refreshed” when the Event.RESIZE is triggered. This property is useful if you have a lot of DisplayObject and you don’t want to execute some useless code.
ElementUI
Property: autoRefresh (default true)
See BaseUI autoRefresh description above.
Properties: forceReferenceHeight and forceReferenceWidth
BaseUI is using width and height to set the position of the DisplayObject, sometimes the size can be disturbed by mask or components. They are some properties to help you handle these problems, for example: useInitialSize or bypassSize. I’ve added these two properties and they are the strongest reference that will be used for calculate a new position.
Other layouts will be built, at least a Grid and another Canvas to handle overlapping. I'm basically waiting the official Flash Player 10 release as it has a nice text layout manager!
I’ll write a complete tutorial in the future, let’s see the layouts classes in details.
HBoxUI, VBoxUI and TileUI are subclasses of CanvasUI that is a subclass of MovieClip.
A canvas is containing:
- a Wrapper to handle the size of the canvas
- a Sprite container containing the children added in the canvas
- a Mask to hide the content that is outside of the canvas (optional)
- a Scrollpane component to handle scrollbars if the content is bigger than the canvas (optional)
CanvasUI
The main meaning of a canvas is having an area you can resize without having the content resized. As in Flex, the canvas is an absolute layout and children can overlap. It will be possible to handle some behaviors impossible without. It is also the easiest way to have a centered fixed area in the browser and easily handle ElementUI inside.
To create a canvas:
-
var canvas:CanvasUI = new CanvasUI();
A canvas constructor can take 4 optional parameters: width, height, layoutScroll, layoutMask. By default, CanvasUI build a mask to show only the content within the size specified and creates scrollbars (scrollpane instance) if the content is bigger than the size specified. If you don’t need the mask or the scrollbar, just set them to false when you create the instance. If you set the layoutScroll to false, you don’t need a scrollpane component in the flash library (or SWC for Flex SDK user), it will not be imported or created. For example:
-
var canvas:CanvasUI = new CanvasUI(200, 200, false, false);
A canvas has a background color and alpha (default is 0), you can set those values if you want to see your canvas:
-
canvas.canvasColor = 0xFF0000;
-
canvas.canvasAlpha = 0.5;
You can use all the ElementUI properties, for example: top, bottom, width, ratio, etc… straight on the canvas. The only difference, unlike ElementUI, the width and height percentage is set with others properties (percentWidth and percentHeight). For example:
-
canvas.horizontalCenter = 0;
-
canvas.percentWidth = “80%”; // or “80” or 80
-
canvas.bottom = 20;
-
canvas.height = 300;
A canvas has an internal BaseUI instance (for wrapper, mask and scrollpane) and another for the children. The internal BaseUI instance has the property autoRefresh set to false to keep good performance. It means when you are done setting the properties for the canvas, you must refresh it (this is only for the canvas, you don’t need to do that after adding children):
-
canvas.refresh();
You can add children as you would do with a Sprite or other DisplayObjectContainer using the addChild method. You can also use addChildUI to add a child and an ElementUI instance will be created. You can also set ElementUI properties on the children, for example:
-
var el:ElementUI = canvas.addChildUI(mySprite);
-
el.ratio = ElementUI.RATIO_IN;
-
el.properties = {top:10, bottom:10, left:10, right:10};
You have some methods to get or remove the ElementUI (see documentation):
-
var el:ElementUI = canvas.getChildUI(mySprite);
-
canvas.getChildUI(mySprite).bottom = 20;
-
canvas.getChildUIByName("mySprite").right = 20;
-
canvas.removeChildUI(mySprite);
CanvasUI is a mix between inheritance and polymorphism to make behaviors working properly. Most of the MovieClip methods and properties are accessible from the canvas instance. You might find some missing or not working properly, testing all methods and properties between DisplayObjectContainer and MovieClip is a hudge work as some are applied on the wrapper, others on the canvas and others on the container. If you’ve got a problem, you can access to the internal elements through properties (see the documentation).
HBoxUI, VboxUI and TileUI
These layouts are subclassing the CanvasUI and you’re not free to set the position of the children, they are calculated internally. You’ll find some properties common in the Flex layouts.
HBox horizontally lays out its children one by one, you have access to properties like horizontalGap, alignChildren, verticalCenterChildren and padding. Here is an example:
-
var hbox:HBoxUI = new HBoxUI();
-
addChild(hbox);
-
hbox.horizontalGap = 5;
-
hbox.alignChildren = HBoxUI.ALIGN_CENTER;
-
hbox.verticalCenterChildren = 40;
-
hbox.padding = new Padding(10, 10, 25, 10);
-
hbox.name = "hbox";
-
hbox.reference = this;
-
hbox.percentWidth = "50%";
-
hbox.height = 200;
-
hbox.right = 20;
-
hbox.bottom = 20;
-
hbox.canvasAlpha = .4;
-
hbox.refresh();
-
hbox.addChild(mySprite1);
-
hbox.addChild(mySprite2);
-
hbox.addChild(mySprite3);
VBox vertically lays out its children one by one, you have access to properties like verticalGap, alignChildren, horizontalCenterChildren and padding. Here is an example:
-
var vbox:VBoxUI = new VBoxUI();
-
addChildUI(vbox);
-
vbox.alignChildren = VBoxUI.ALIGN_CENTER;
-
vbox.horizontalCenterChildren = 40;
-
vbox.padding = new Padding(10, 25, 10, 10);
-
vbox.name = "vbox";
-
vbox.reference = this;
-
vbox.percentWidth = "50%";
-
vbox.height = 200;
-
vbox.right = 20;
-
vbox.bottom = 20;
-
vbox.canvasAlpha = .4;
-
vbox.refresh();
-
vbox.addChild(mySprite1);
-
vbox.addChild(mySprite2);
-
vbox.addChild(mySprite3);
TileUI lays out its children in a grid of equal-sized cells. You can set additional properties like horizontalGap, verticalGap, direction and padding. Here is an example:
-
var tile:TileUI = new TileUI();
-
addChildUI(tile);
-
tile.direction = TileUI.DIRECTION_HORIZONTAL;
-
tile.padding = new Padding(10, 10, 10, 10);
-
tile.name = "tile";
-
tile.reference = this;
-
tile.percentWidth = "50%";
-
tile.height = 200;
-
tile.right = 20;
-
tile.bottom = 20;
-
tile.canvasAlpha = .4;
-
tile.refresh();
-
tile.addChild(mySprite1);
-
tile.addChild(mySprite2);
-
tile.addChild(mySprite3);
Demo Tween
It is not working smoothly in some browsers (Firefox seems the slowest one), but you can easily tween a new position and size after a resize event. ElementUI is using an Event before applying the new values to the DisplayObject. You can add a listener, stop the propagation and handle yourself the movements. The demo link is at the end of the post or in the source.
I’ve included the demos in the source, Flex SDK users and Linux users will find a SWC of the Scrollpane classes and skin.
Hope you like it and find it useful.
Demo BaseUI
Demo CanvasUI
Demo HBoxUI
Demo VBoxUI
Demo TileUI
Demo Tween

Entries (RSS)
August 13th, 2008 at 6:21 pm
WOW can't wait to try it
thank you!!
August 14th, 2008 at 7:00 am
really nice! thanks for sharing
August 29th, 2008 at 8:09 pm
Awesome stuff.
I have question though. Is there an easy way to add an object with percentWidth other than the canvas? ie. Say you want to add a textField to the canvas that is always 50% of the canvas width.
Thanks,
Guy
August 31st, 2008 at 12:43 am
Sure, the percentWidth and percentHeight are special properties of CanvasUI but you can use the width and height properties of an ElementUI with a percent value.
This should do the job:
var canvas:CanvasUI = new CanvasUI();
// set 50% width and height for the canvas
canvas.percentWidth = "50%"; // or canvas.percentWidth = "50"; or canvas.percentWidth = 50;
canvas.percentHeight = "50%";
var el:ElementUI = canvas.addChildUI(myTextField);
// set 50% width and height for the textfield
el.width = "50%";
el.height = "50%";
September 2nd, 2008 at 9:11 pm
Seriously wonderful stuff! You've considered different wants for the inputs and usage and have done a nice job of complying with the current Flex standard/model.
Question:
How do you get multiple objects in the layout package to "fit inside each other"? In other words, I'm wanting to place a two vbox'es inside one hbox.
September 2nd, 2008 at 9:51 pm
Also, do you have any plans for a minWidth and minHeight for the ElementUI? How do you feel about other updating the source code?
September 3rd, 2008 at 9:22 pm
Romuald, I believe I've found a bug. http://posting.imitationstudios.com/baseUI/baseUI_possibleBug.zip
It appears to be just a timing of the drawing...
September 3rd, 2008 at 9:33 pm
Romuald, on the bug above: Just try resizing the Flash Stand-Alone Player window when you publish the swf from the IDE.
September 4th, 2008 at 12:28 am
Hi john,
A VBoxUI in HBoxUI won't work at the moment (version 3.0), it shouldn't be a big deal but I just didn't do it yet. It will work in a CanvasUI though if you want to calculate the positions of the children yourself. I've added it in my TODO list for the next release, thanks for your input.
About the bug, I'm not sure it is really one.
The problem is: your Area movie get always resized (the width and height change) by the first BaseUI and the rectangle inside get also resized by a second BaseUI. The rectangle is resized 2 times by the 2 BaseUI instances.
Basically, I built the layouts to handle this kind of problem. If you change the width and height of a sprite, everything inside will be also resized, which is not the case with a CanvasUI instance, the children will keep their size. In your example, you can even remove the BaseUI in the Area class, draw a rectangle with any values like 100*100 as the Area movie will be resized to 80%. Add a centered rectangle 50*50 in the Area class and you get what you want to reach. This is working if you don't care that the Sprite and its children are resized, otherwise you have to use a CanvasUI.
If you want a main movie set to 80% width and height and a child movie set to 50% width and height of the main movie. I would create the main movie as a CanvasUI and set the children size. This should do what you're trying to do:
var area:CanvasUI = new CanvasUI();
area.canvasColor = Math.random()*0xFFFFFF;
area.canvasAlpha = .5;
area.percentWidth = area.percentHeight = "80%";
var el:ElementUI = area.addChildUI(myRectangle);
el.width = el.height = "50%";
area.refresh();
If you want to add specific code in your area, just extend CanvasUI or use a simple sprite and add the canvas instance inside. The second solution is simpler and very often polymorphism is more flexible.
The other solution would be use only one BaseUI and have both the Area and the rectangle in the same movie clip (your main class for example), so the rectangle is not anymore a children of the Area class but of the main movie, if this fit what you want to do, it is very simple and make you use flash with layouts like you would do in Photoshop.
I hope it helps, if you can't reach what you need, send me an email and I'll try to help.
I probably should open a group or a forum to discuss this kind of problem.
Thanks anyway.
About minWidth and minHeight, the first version of BaseUI (in AS2 and not released) handled it in a way, but it makes things a lot more complicated, I'll think about.
I might take other people on the project if they are interested and if BaseUI if used by a lot of people, we'll see
Romu
September 4th, 2008 at 9:11 pm
* "I've added it in my TODO list for the next release, thanks for your input."
Great thanks!
* "If you want to add specific code in your area, just extend CanvasUI or use a simple sprite and add the canvas instance inside. The second solution is simpler and very often polymorphism is more flexible."
Totally agree and will do. Thank you very much for the explanation. I've read your notes throughout your classes and found it helpful as well.
* I understand that the mins would add much complexity to the project.
* Look forward to the revisions and a possible group forum and additional man power on this project.