How to Use Flex Layout
by Alaric Cole, Senior Flex Developer
Coming from a Flash background, laying out your application in Flex is extremely easy. You can visually place things where you like, drag and drop, and resize on-the-fly. No longer limited to a static layout, you can quickly create a user interface (UI) that resizes to fit varying screens, or even layout that is customizable by the user. The Flex layout system inherits many concepts from HTML and CSS, so having a background in web design is a big plus. But it's easy for anyone to get started, as Flex Builder will do most of the work for you. In this article we'll discuss some of the basics of layout, using absolute positioning, layout containers and controls, and a few tips to keep you on track.
- What You Need
- Absolute Positioning and Constraints-based Layouts
- Using Layout Containers
- Using Layout Controls
- Diagramming Your Layout
- Using Percentage-based Sizes
- Flex Builder 3 (Trial version available for download on Adobe.com)
- Basic knowledge of MXML
By default, a new Flex application will begin with absolute positioning by the property layout="absolute". This is akin to CSS layers, where any item (or container) is laid out with x,y coordinates. This allows complete control over where objects are placed, and can even allow overlap of items. With the layout property set to "absolute", the Application is like a giant Canvas, which feels like a graphics application or the Flash IDE (but with lots of extras). Most users will find it easier to begin with this default and add Flex containers as necessary.
Opening up Flex Builder in Design View, you can rapidly set up your layout. Just drag and drop to place things where you want them for the size of your canvas; later when you want to think about resizing for different screens you can convert to a constraint-based layout. Design View will do most of this automatically for you. For example, say you've placed a button in the bottom right corner of a 500 x 500 pixel canvas, effectively setting its x to 425 and its y to 468. You can then tell Flex to snap the button to that right corner so when the screen or browser window is resized it will stay in the corner.
Doing so would turn this:
Into a constraints-based layout:
Which translates to "Make this button stay 10 pixels from the right and 10 pixels from the bottom, resizing itself or moving around as necessary."
If you will add and remove elements at runtime, you should consider taking advantage of the basic Flex containers such as HBox, VBox, or Panel. These containers stipulate where elements go relative to one another, instead of each element having an x,y. The HBox is short for "Horizonal Box", and groups a set of elements horizonally; knowing that, I'm sure you can guess what VBox does. A Panel can line things up horizonally, vertically, or absolutely, and adds some nice chrome that looks like a UI window.
If you need more refined control over layout than simple horizontal and vertical placement, you may find the more advanced containers such as Grid or Form (and their subcontainers GridItem and FormItem) useful. If you expect to create, say, a portfolio of images in a grid layout, you would want to use a Grid; otherwise you would have to set the x,y of each control manually, based on the cumulative sizes of the others. Using containers makes things much easier.
There are also a handful of UI controls that are useful for layout. They can be thought of as supplementing layout containers. The Spacer is an invisible control that can have a width and height, so when used in conjunction with layout containers it helps to push other controls around. For instance, a Spacer placed inside an HBox could separate the controls to its left and right, pushing them apart. An HRule or VRule works similarly to a Spacer, but shows a thin horizontal or vertical line. People like to use them in Form containers to add visual separation of content.
You may find it useful to diagram your layout first, which will help you think about how different elements relate. Once this is done, it should be easy to plug in the proper layout containers in Flex and test it in Design View. For example, to create a 'typical' Yahoo! layout with a header, main content area of 600 pixels, and ads on the right, you might diagram the following:
Which could translate to:
Note that if you wanted the above Content area to be 'stretchy,' i.e. resize to it's container, you could stipulate a 100% width for the YourContent area. If it contained something like blocks of text that you wanted to stretch but didn't want wider than 600 pixels (for readability), you can set the maxWidth property to 600 pixels. That way it will stretch to 100% of its available area, but not more than 600 pixels.
The trick is to use as few nested containers as possible. While this will also give a performance boost, more importantly for you is that it's easier to understand what's going on. A Flex Application is pretty much a container with some additional functionality. Since it can take a layout of horizontal, vertical, or absolute, it can work just like an HBox, VBox, or Canvas. If you find that one of these layouts works for you, you will not need to nest an additional HBox, etc. within the Application -- it will do the job itself.
For example, these three layouts will all display identically to the user, though they are coded differently:
The first and second use a Spacer component to "push" the right Button to the far right, while the third uses absolute positioning to "snap" the left Button one pixel from the right edge. The second and third are more efficient, taking advantage of the layout property of the Application container: Instead of placing an extra HBox within the Application, just telling the Application to line up its content horizontally is less verbose and easier to read.
If two (or more) items within an HBox, VBox, or other container use percentage-based widths, they will compete for that space. For example, for two items with their width set to 100%, their effective width will be 50% each (100% divided by two for the math buffs). The same goes for, say, a Button with a width of 35px and Label with a width of 100%. The effective width of the Label will be 100% - 35px. It is useful to note that some controls such as Label do not visually extend to the limits of their width or height; their visible parts may be much smaller. So a Label can be used much like a Spacer control to take up space and push things around.
Remember that when using percentage-based sizes you are referring to a percentage of the size of the parent container. If the parent container does not contain its own sizing information, the percentage has nothing to refer to and will be ignored.
So, if using a percentage-based width on a control, for instance a Button, you need to set a width on the parent container. If using a pixel-based width on a Button, you have these choices:
- Do not set a size on the container. This will allow the container to resize as necessary to contain the Button. If it runs out of room a scrollbar will appear.
- Do set a size on the container. Scrollbars will appear if the Button's sizes are larger than the container's.
If using percentage-based sizes on a container, you have these options:
- Do not set a size for a control. The default size of the control will take over, and scrollbars will appear if the controls are larger than the container.
- Do set a size for a control. Scrollbars will appear if the controls are larger than the container.
For example, the following will cause the Panel to display a horizontal scrollbar:
While removing the explicit width for the Panel will allow it to resize to fit the Image:
A typical issue for beginners is a scrollbar showing up when you don't need (or want) them. One way to combat this is to avoid using explicit heights or widths until absolutely necessary. Setting an explicit height or width is useful to avoid resizing of a component or container, and it may also run more efficiently, but may be more trouble than its worth. Try laying things out with few explicit sizes or sizes of 100%. Later in the development cycle, when you're certain about everything, you can define more sizes to optimize.
Alignment can be tricky at first. Each container is set up to resize to the contents of its children if no other size has been instructed. So, if you have something you want centered in your application, but don't have an explicit size for the container, the alignment won't be noticed. A common mistake is to then go up the hierarchy of containers, setting the horizontalAlign property again and again. However, the issue is often due to the sizing of the container, not the alignment. If you set an explicit size, say 100% width, then the container will be larger than its children, allowing the alignment to show. Note that this same rule will apply to any parent containers who don't have explicit sizes.
This doesn't work so well:
Experience is key, and the best way to learn is to experiment with laying out interfaces in Flex. It's easy to get started, and the most basic of layouts can usually be done and forgotten about. With a more complex layout, it is a good idea to do a little planning. By following a few best practices and thinking about your layout before you begin coding, you will save a lot of time and frustration.