Positioning components

The position of a component is defined by the x and y coordinates of its top, left corner in its parent container. For most containers, Flex automatically determines the location of the component in its parent container. This is called automatic positioning.

Some containers let you explicitly specify the x and y coordinates of the component in it parent container. This is called absolute positioning. These containers include the following:

  • A Spark container using the BasicLayout class

  • The MX Canvas container

  • The MX Application and Panel containers with the layout property set to absolute

Automatic positioning

With automatic positioning, Flex positions the container children according to the container’s layout rules, such as the layout direction, the container padding, and the gaps between children of that container.

For containers that use automatic positioning, setting the x or y property directly on a child or calling the child’s move() method has no effect, or only a temporary effect. This is because the container recalculates the child’s position and does not use the specified value. You can, however, specify absolute positions for the children of these containers under some circumstances; for more information, see below.

You can control aspects of the layout by specifying container properties; for details on the properties, see the property descriptions for the container in the ActionScript 3.0 Reference for the Adobe Flash Platform. You also control the layout by controlling component sizes and by using techniques such as adding spacers.

Using the Spacer control to control layout

Flex includes a Spacer control that helps you lay out children within a parent container. The Spacer control is invisible, but it does allocate space within its parent.

In the following example, you use a percentage-based Spacer control to push the Button control to the right so that it is aligned with the right edge of the HBox container:

<?xml version="1.0"?>
<!-- components\SpacerHBox.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>
    
    <fx:Script>
        <![CDATA[
            [Embed(source="assets/flexlogo.jpg")]
            [Bindable]
            public var imgCls:Class;
        ]]>
    </fx:Script> 
    
    <s:SkinnableContainer width="400">
        <s:layout>
            <s:HorizontalLayout/>
        </s:layout>
        <mx:Image source="{imgCls}"/>
        <s:Label  text="Company XYZ"/>
        <mx:Spacer width="100%"/>
        <s:Button label="Close"/> 
    </s:SkinnableContainer>
</s:Application>

The executing SWF file for the previous example is shown below:

In this example, the Spacer control is the only percentage-based component in the parent container. Flex sizes the Spacer control to occupy all available space in the container that is not required for other components. By expanding the Spacer control, Flex pushes the Button control to the right edge of the container.

You can use all sizing and positioning properties with the Spacer control, such as width, height, maxWidth, maxHeight, minWidth, and minHeight.

Disabling automatic positioning temporarily

You can use effects, such as the Move and Zoom effects, to modify the size or position of a child in response to a user action. For example, you might define a child so that when the user selects it, the child moves to the top of the container and doubles in size. These effects modify the x and y properties of the child as part of the effect. Similarly, you might want to change the position of a control by changing its x or y coordinate value, for example, in response to a button click.

Containers that use automatic positioning ignore the values of the x and y properties of their children during a layout update. Therefore, the layout update cancels any modifications to the x and y properties performed by the effect, and the child does not remain in its new location.

You can prevent Flex from performing automatic positioning updates that conflict with the requested action of your application by setting the autoLayout property of a container to false. Setting this property to false prevents Flex from laying out the container’s contents when a child moves or resizes. The default value is true, which enables Flex to update layouts.

For MX containers only, even when you set the autoLayout property of a container to false, Flex updates the layout when you add or remove a child. Application initialization, deferred instantiation, and the <mx:Repeater> tag add or remove children, so layout updates always occur during these processes, regardless of the value of the autoLayout property. Therefore, during container initialization, Flex defines the initial layout of the container children regardless of the value of the autoLayout property.

The following example disables layout updates for a VBox container:

<?xml version="1.0"?>
<!-- components\DisableVBoxLayout.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>
    
    <mx:VBox id="vb1" autoLayout="false" 
        width="200" 
        height="200">
        <s:Button id="b1" 
            label="Button 1"/>
        <s:Button id="b2" 
            label="Button 2"
            click="{b2.x += 10; vb1.invalidateDisplayList();}"/>
        <s:Button id="b3" 
            label="Button 3"
            creationComplete="b3.x = 100; b3.y = 75;"/>
    </mx:VBox>
</s:Application>

The executing SWF file for the previous example is shown below:

In this example, Flex initially lays out all three Button controls according to the rules of the VBox container. The creationComplete event listener for the third button is dispatched after the VBox control has laid out its children, but before Flex displays the buttons. Therefore, when the third button appears, it is at the x and y positions specified by the creationComplete listener.

After the buttons appear, Flex shifts the second button 10 pixels to the right each time a user clicks it. The button click also triggers the container to update its layout by calling the updateDisplay() method.

Setting the autoLayout property of a container to false prohibits Flex from updating a container’s layout after a child moves or resizes, so you should set it to false only when necessary. You should always test your application with the autoLayout property set to the default value of true, and set it to false only as necessary for the specific container and specific actions of the children in that container.

For more information on effects, see Introduction to effects.

Preventing layout of hidden controls

By default, Flex lays out and reserves space for all components, including hidden components, but it does not display the hidden controls. A hidden component is one with its visible property set to false. You see blank spots where the hidden controls should appear when you make them visible. In place of the hidden controls, you see their container’s background.

However, you can prevent Flex from considering the child component when it lays out the container’s other children by setting the child component’s includeInLayout property of the component to false.

When a component’s includeInLayout property is false, Flex does not include it in the layout calculations for other components. In other words, Flex does not reserve space for the component, but still draws it. As a result, the component can appear underneath the components that follow it in the layout order. To prevent Flex from drawing the component, you must also set its visible property to false.

The following example shows the effects of the includeInLayout and visible properties. It lets you toggle each of these properties independently on the middle of three Panel controls in a SkinnableContainer:

<?xml version="1.0"?>
<!-- components\HiddenBoxLayout.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"
    height="500">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>
    
    <s:SkinnableContainer>
        <s:layout>
            <s:VerticalLayout/>
        </s:layout>
        <s:Panel id="p1" 
            title="Panel 1"/>
        <s:Panel id="p2" 
            title="Panel 2"/>
        <s:Panel id="p3" 
            title="Panel 3"/>
    </s:SkinnableContainer>

    <s:SkinnableContainer>
        <s:layout>
            <s:HorizontalLayout/>
        </s:layout>
        <s:Button label="Toggle Panel 2 Visible" 
            click="{p2.visible=!p2.visible;}"/>
        <s:Button label="Toggle Panel 2 in Layout" 
            click="{p2.includeInLayout=!p2.includeInLayout;}"/>
    </s:SkinnableContainer>
</s:Application>

The executing SWF file for the previous example is shown below:

Run this application and click the buttons to see the results of different combinations of visible and includeInLayout properties. The example shows the following behaviors:

  • If you include the second Panel container in the layout but make it invisible, Flex reserves space for it.

  • If you exclude the second Panel container from the layout, the SkinnableContainer resizes and the third Panel container moves up. If you then include the second Panel container in the layout, the SkinnableContainer resizes again, and the third Panel container moves down.

  • If you exclude the second Panel container from the layout but make it visible, Flex still draws it, but does not consider it in laying out the third Panel container, so the two panels overlap.

Absolute positioning

With absolute positioning, you specify the position of the child by setting its x and y properties, or you specify a constraint-based layout; otherwise, Flex places the child at position 0,0 of the parent container. When you specify the x and y coordinates, Flex repositions the controls only when you change the property values.

The following example uses absolute positioning to place two Spark BorderContainer containers inside a SkinnableContainer. Absolute positioning is the default layout of a SkinnableContainer:

<?xml version="1.0"?>
<!-- components\AbsoluteLayout.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>

    <s:SkinnableContainer
        width="100" height="100">
        <s:BorderContainer id="b1" 
            width="80" height="80" 
            x="20" y="20"
            backgroundColor="#A9C0E7">
        </s:BorderContainer>

        <s:BorderContainer id="b2" 
            width="50" height="50" 
            x="120" y="50"
            backgroundColor="#FF0000">
        </s:BorderContainer>
    </s:SkinnableContainer>
</s:Application>

The executing SWF file for the previous example is shown below:

This example produces the following image:

When you use absolute positioning, you have full control over the locations of the container’s children. This lets you overlap components. The following example moves the second BorderContainer container so that it partially overlaps the first.

<?xml version="1.0"?>
<!-- components\AbsoluteLayoutOverlap.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>

    <s:SkinnableContainer
        width="100" height="100">
        <s:BorderContainer id="b1" 
            width="80" height="80" 
            x="20" y="20"
            backgroundColor="#A9C0E7">
        </s:BorderContainer>
        
        <s:BorderContainer id="b2" 
            width="50" height="50" 
            x="0" y="50"
            backgroundColor="#FF0000">
        </s:BorderContainer>
    </s:SkinnableContainer >
</s:Application>

The executing SWF file for the previous example is shown below:

This example produces the following image:

Note: If you use percentage-based sizing for the children of a control that uses absolute positioning, the percentage-based components resize when the parent container resizes, and the result may include unwanted overlapping of controls.