This is part two of a look into custom layouts in Flex 4. Be sure to read part 1 first.

Creating a custom layout

When I first wanted to create a custom layout in Flex 4, I thought a good place to start would be to look at the default Horizontal or Vertical layout. If you do this you will be presented with roughly 2000 lines of code, which as I’m sure you’ll agree isn’t exactly the simplest way get started.

You would think, perhaps as I did, that a horizontal layout would simply loop though all the elements in a group and set each ones x property to the with of the previous element. Essentially this is true, however the default Horizontal layout also needs to consider a few other things including:

  • Horizontal align (left/right/center)
  • Vertical align (top/bottom/middle)
  • Horizontal Gaps
  • Padding (top/right/bottom/left)
  • Variable element size
  • Virtual elements
  • Keyboard navigation
  • Element percent height
  • Drag and drop support

As you can see there is quite a lot of functionality delegated to layouts in flex 4, asides from just positioning the elements. However don’t let this put you off, as chances are if your creating a simple layout you won’t be worried about may of these considerations. If you find you need to implement them later, you can add support as required.

With simplicity in mind I have decided to create a very simple layout in order to demonstrate how easy it can be, and help get you started.

A simple custom layout

In order to create out layout we need to start by extending the LayoutBase class. This will give us the basic methods and the correct type to ensure compatibility with Spark groups.

public class StackedLayout extends LayoutBase
{
 
}

The next thing to do is override the updateDisplayList() method, so we can take charge of laying out the elements in the target group (this is the group that the layout has been assigned to).

public class StackedLayout extends LayoutBase
{
	override public function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
	{
		// Set the layout bounds (position) of each element in the target group
		// Update the target's size (for the scroller)
	}
}

It is also suggested that you implement a custom measure() implementation by overriding it. However in our example the group is in a scroller that we are sizing explicitly. Therefore we don’t need to worry about setting it’s measured sizes, so won’t implement it for simplicity.

Next we need to iterate though the elements in the target group and position each one using the setLayoutBoundsPosition(x,y). We can get a reference to elements using the getElementAt() method on the target group.

In this example we are creating a stacked layout, which overlaps all the elements like partially spread deck of cards. To do this we will move each element 10 pixels to the right of the previous one.

    public class StackedLayout extends LayoutBase
    {
        override public function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            var currentGroup:GroupBase = target; // The current group whos content we are layout out
            var x:Number = 0; // The x position which we will increase to move each element along
            var currentLayoutElement:ILayoutElement; // The current layout target (in our demo this is one of the images)
 
            // Iterate through all the elements in the target so we can position it
            for (var i:int = 0; i < currentGroup.numElements; i++)
            {
                currentLayoutElement = target.getElementAt(i);
				currentLayoutElement.setLayoutBoundsSize(NaN, NaN); // Sizes the element to it's default size
                currentLayoutElement.setLayoutBoundsPosition(x, 0);
                x += 10;
            }
        }
    }

Finally we need to update the content size on the target, so the scroller knows how big the group is and can decide if scroll bars are needed. This is done using the setContentSize()

 
    public class StackedLayout extends LayoutBase
    {
        override public function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            var currentGroup:GroupBase = target; // The current group whos content we are layout out
            var x:Number = 0; // The x position which we will increase to move each element along
            var currentLayoutElement:ILayoutElement; // The current layout target (in our demo this is one of the images)
 
            // Iterate through all the elements in the target so we can position it
            for (var i:int = 0; i < currentGroup.numElements; i++)
            {
                currentLayoutElement = target.getElementAt(i);
				currentLayoutElement.setLayoutBoundsSize(NaN, NaN); // Sizes the element to it's default size
                currentLayoutElement.setLayoutBoundsPosition(x, 0);
                x += 10;
            }
 
            // Set the content size, so it can be scrolled
            // This is the current x value plus the width of the last element. There is only one row, so the height is the same as an element height
            currentGroup.setContentSize(x + currentLayoutElement.getPreferredBoundsWidth(), currentLayoutElement.getPreferredBoundsHeight());
        }
    }

Demo

I have put the above example together with the last demo, and added the ability to change the height and width of the scroll, so you can see how it works with setting the content size.

You can download the example code here.

This demo has been created with simplicity in mind and as we explore layouts in more detail you will see how we can improve the code to work in more situations and be more customisiable and resilliant. Read part three here.

This entry was posted on Thursday, November 18th, 2010 at 2:48 pm and is filed under ActionScript, AIR, Flex. You can leave a comment and follow any responses to this entry through the RSS 2.0 feed.

2 Comments Leave a comment

  1. [...] In part two we look into creating a simple layout. Read part two here. [...]

  2. [...] is part three of a look into custom layouts in Flex 4. Be sure to read part 1 and part 2 [...]

Leave a Reply