Share 'Layouts' on Delicious Share 'Layouts' on Facebook Share 'Layouts' on Google Bookmarks Share 'Layouts' on Twitter

  1. Features
  2. The Layouts
  3. General Usage
    1. Requirements
    2. Basic Setup
    3. Shortcut API vs Standard API
    4. Adding Items
    5. The layout() Method
    6. Layout configuration
    7. The Display
  4. Advanced Topics
    1. Addressing Items
    2. Configuring Individual Cells
    3. Excluding / Including Items
    4. Nesting Layouts
    5. Applying Transitions
    6. Relayouting
    7. Layout Debugger
    8. Layout Info
  5. Comments (28)
  6. Leave a Comment

Layouts

Layouts is a clean yet powerful layouting framework containing a set of horizontal and vertical layouts accompanied by an intuitive API that provides rich customization possibilities.

Teaser.swf

See the different layouts in action to get an idea of what Layouts does.

Features

Rich configuration capabilities

There is a number of configuration properties to refine a layout configuration. There are margins, offsets, alignments, gaps or maximum bounds, to name a few.

Custom configuration of individual items

It is possible to assign layout properties to individual display objects. Think of a line of boxes where only one box has a particular vertical offset.

Addressing items

Layouts supports items not being stored in local variables. To anyhow operate on those items at a later time, it is possible to assign items a unique id to that can be referred to.

Excluding / Including of items at runtime

One major feature of Layouts is formed by the exclude/include mechanism. Items can be excluded from being considered in the calculation of space and positions and – at a later time – included again to show up at the right place.

Nested layouts

Layouts can be nested wihout limitation. It is possible to selectively relayout only such a nested layout instead of doing a full refresh of the entire structure.

Transition support via layouting callbacks

It is possible to hook into the layout process to create attractive transitions rather than simply moving objects from here to there.

Shortcut API available

A shortcut API lets setup layouts in a more readable way.

Relayouts at any time

Layouts can be refreshed at any time to reflect changes in content or configuration.

Small footprint (file size, memory, cpu)

All these layouts are developed and optimized with performance considerations in mind.

The Layouts

Layout Shortcut Capabilities
HGroup hgroup Horizontal single line layout
VGroup vgroup Vertical single line layout
HLayout hlayout Horizontal multi-line layout, row breaks on maxContentWidth and/or maxItemsPerRow, same as HGroup if neither specified
VLayout vlayout Vertical multi-line layout, column breaks on maxContentHeight and/or maxItemsPerColumn, same as VGroup if neither specified
Table table (Horizontal) table layout, numColumns expected, same as HGroup if not specified
DynTable dyntable (Horizontal) table layout with runtime calculated optimal column number, maxContentWidth expected, same as HGroup if not specified

See the different layouts in action.

All layouts are non-visual components

The layouts are just mathematical objects. They are not and do not create display objects. Nested layouts are bare mathematical objects as well. Items managed by nested layouts usually live in the same display object container. The layouts and their nested combinations can be thought as position managers for the contents of specific visual containers.

General Usage

Requirements

Layouts relies on the width and height properties of the display objects to be layouted. You need to make sure that these properties are set and return the actual size of the component at the time the layout.layout() method is execuded.

Within its layout() method, a particular layout will add all assigned objects to the container to be layouted if not done before. If your component does not have initial dimensions, you need to perform some initializing right in the constructor of the component so that width and height are set and reflect the actual component size. Otherwise the layout assumes the component has no size and won’t consider the component at all.

You may force a component size by overriding the DisplayObject's width and height properties:

1
2
3
4
5
6
7
8
9
override public function get width() : Number {
  return _width; // returns self-managed width
  return 100; // returns fix width
}

override public function get height() : Number {
  return _height; // returns self-managed height
  return 100; // returns fix height
}

Basic Setup

Layouting a display object container is a 3 step procedure:

  1. Create a layout instance
  2. Assign display objects
  3. Invoke the layout command
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package layout.general {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.HGroup;
  import flash.display.Sprite;

  public class GeneralUsage extends Sprite {
    public function GeneralUsage() {
      var layout : HGroup = new HGroup();
      layout.add(new Box());
      layout.add(new Box());
      layout.add(new Box());
      layout.layout(this);
    }
  }
}
GeneralUsage.swf

Shortcut API vs Standard API

Layouts provides an additional shortcut API that reduces code quantity and increases code readability. All operations of the standard API (see APIDoc) are available in the shortcut API, too.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package layout.general {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.HGroup;
  import org.as3commons.ui.layout.shortcut.hgroup;
  import flash.display.Sprite;

  public class ShortcutAPI extends Sprite {
    public function ShortcutAPI() {
      var layout : HGroup = hgroup(
        new Box(),
        new Box(),
        new Box()
      );
      layout.layout(this);
    }
  }
}
ShortcutAPI.swf

Adding Items

A layout only considers items that have been added explicitely. There are different ways to add items to a layout.

Adding a single or a list of items

The add() method accepts a single or a list of arguments. A single argument can be an array or even a nested array of display objects. You can add objects already included in the display or objects not being included. The layout then will add these objects within the layouting procedure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package layout.general {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.HGroup;
  import flash.display.Sprite;

  public class AddingItems extends Sprite {
    public function AddingItems() {
      var layout : HGroup = new HGroup();
      layout.add(new Box());
      layout.add(new Box(), new Box(), new Box());
      layout.add(Box.create(3)); // Array
      layout.add(new Box(), Box.create(2));
      layout.layout(this);
    }
  }
}
AddingItems.swf

Adding items in front

The addFirst() method works equally to add(). The order of the items passed to this method is kept.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package layout {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.HLayout;
  import flash.display.Sprite;

  public class AddFirst extends Sprite {
    public function AddFirst() {
      var h : HLayout = new HLayout();
      h.maxItemsPerRow = 5;
     
      h.add(Box.create(5)); // 1-5
      h.addFirst(Box.create(5)); // 6-10,1-5
      h.add(Box.create(5)); // 6-10,1-5,11-15
      h.addFirst(new Box(true)); // 16,6-10,1-5,11-15
      h.add(new Box(true));// 16,6-10,1-5,11-15,17

      h.layout(this);
    }
  }
}
AddFirst.swf

Adding items in bulk

It is possible to add all children of a specified container at once using the addAll(container) method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package layout.general {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.HGroup;
  import flash.display.Sprite;

  public class AddAll extends Sprite {
    public function AddAll() {
      addChild(new Box());
      addChild(new Box());
      addChild(new Box());
      addChild(new Box());
      addChild(new Box());
     
      var layout : HGroup = new HGroup();
      layout.addAll(this);
      layout.layout(this);
    }
  }
}
AddAll.swf

The layout() Method

You execute the layout procedure by invoking the layout(container) operation. This can be repeated multiple times. The routine creates a small amount of data necessary to calculate the particular item positions, moves the items to the calculated locations and cleans up all runtime created data so that only the layout configuration properties and the list of added items are persistent.

Items not yet added to the display list or items whose parent does not equal to the given layout container are added automatically to that container. The most of the examples on this page show this feature.

Layout configuration

There are several common layout properties and a few distinctive. The following table describes the meaning of all of these properties.

id Assigning an id to a layout or a layout item (Display, see next section) enables us to later refer to that item without storing the item’s instance in our code.
marginX, marginY The distance to the actual item position (before margin was applied). Succeeding items are affected and moved.
offsetX, offsetY A simple shift. The distance to the actual item position (before offset was applied). Succeeding items are not affected and not moved.
minWidth, minHeight Minimal dimensions of a layout. Assigning min dimensions has two effects: The layout is guaranteed to extend at least to these values and succeeding items will be positioned in respect to. Secondly, ther alignment of layouts (hAlign, vAlign) works only if these minimal dimensions are greater than the actual layout content.
maxContentWidth or maxContentHeight Available only for multiline layouts. These values define the line break in multiline layouts.
maxItemsPerRow or maxItemsPerColumn Available only for multiline layouts. These values define the line break in multiline layouts.
numColumns Available only for the Table layout. Mandatory there.
gap, hGap, vGap Space between child items
hAlign, vAlign Alignment of the layout within its dimensions. Works only if minWidth, minHeight are specified and greater than the actual content.
excludeFromLayout(hide=true), includeInLayout(show=true) Each layout and layout item (Display, see next section) may be excluded from being considered in the calculation of space and positions. There are flags to control if an affected item should be hidden or shown automatically.

The Display

The Display is nothing special but a wrapper of a single display object. Layouts internally store assigned display objects always wrapped into a Display. But this is transparent to you unless you want to differently configure an individual display object. Then you need to wrap the object with a Display instance and assign that wrapper the desired properties. You can think of a Display as a simple layout containing a sole display object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package layout.general {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.HGroup;
  import org.as3commons.ui.layout.shortcut.*;
  import flash.display.Sprite;

  public class Display extends Sprite {
    public function Display() {
      var layout : HGroup = hgroup(
        new Box(),
        new Box(),
        new Box(),
        display(
          "id", "box",
          "marginX", 20, "marginY", 20,
          new Box()
        ),
        new Box(),
        new Box(),
        new Box()
      );
      layout.layout(this);
    }
  }
}
Display.swf

There is another application of the Display. The getLayoutItem() method of a layout returns an ILayoutItem instance. In case of display objects, the return value will be of type Display. To get the actual display object you have to cast the return value like this:

1
var box : Box = Display(layout.getLayoutItem("box")).displayObject as Box;

Note, there is also another way to specifiy individual display object properties – by using cell configurations. See the appropriate chapter on this page.

Advanced Topics

Addressing Items

Layouts is designed to support anonymous items (sub layouts, display objects) that are not necessarily stored in local variables. This feature is meant to reduce code and enhance readability. Not in all – probably in the fewest – cases we really need to assign visual object instances to variables.

A particular layout is capable to return an item instance by id, if the id has been specified beforehand.

All layouts of this package have an id property and can hence be easily registered in their parent layouts. However, to register plain display objects you need to wrap them into a Display. Registered items (sub layouts or display objects) can be later referred to using the layout.getLayoutItem(...args) method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package layout {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.*;
  import org.as3commons.ui.layout.shortcut.*;
  import flash.display.Sprite;

  public class AddressingItems1 extends Sprite {
    public function AddressingItems1() {
      var h : HGroup = hgroup(
        new Box(),
        vgroup(
          "id", "vgroup",
          Box.create(2)
        ),
        new Box(),
        display(
          "id", "lastbox",
          new Box()
        )
      );
     
      var v : VGroup = h.getLayoutItem("vgroup") as VGroup;
      v.marginX = 20;
      v.marginY = 20;
     
      var d : Display = h.getLayoutItem("lastbox") as Display;
      d.marginX = -10;
      d.marginY = 10;
      var box : Box = d.displayObject as Box;
      box.scaleX = box.scaleY = 2;
     
      h.layout(this);
    }
  }
}
AddressingItems1.swf

ID chain

Certain circumstances may force us to engage a contextual item lookup. Lets say we have multiple instances of the same sub layout and we only want to modify the first item of the second sub layout. In such a case we may filter items using a contextual selector like this: layout.getLayoutItem("parent1Id", "parent2Id", "itemId").

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package layout {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.*;
  import org.as3commons.ui.layout.shortcut.*;
  import flash.display.Sprite;

  public class AddressingItems2 extends Sprite {
    public function AddressingItems2() {
      var v : VGroup = vgroup(
        "gap", 10,
        h1("firstrow"), h1("secondrow")
      );
     
      var d : Display = v.getLayoutItem("firstrow", "firstgrid", "firstbox") as Display;
      d.displayObject.scaleX = d.displayObject.scaleY = 2;
     
      d = v.getLayoutItem("secondrow", "lastgrid", "firstbox") as Display;
      d.displayObject.scaleX = d.displayObject.scaleY = 2;

      var h : HLayout = v.getLayoutItem("secondrow", "firstgrid") as HLayout;
      h.marginX = 40;

      var hg : HGroup = v.getLayoutItem("firstrow") as HGroup;
      hg.gap = 30;

      v.layout(this);
    }

    private function h1(id : String = "") : HGroup { // 4 box grids in a line
      var h : HGroup = hgroup(
        "gap", 10,
        h2("firstgrid"),
        h2(), h2(),
        h2("lastgrid")
      );
      if (id) h.id = id;
      return h;
    }
   
    private function h2(id : String = "") : HLayout { // 2x2 box grid
      var h : HLayout = hlayout(
        "maxItemsPerRow", 2,
        display("id", "firstbox", new Box()),
        Box.create(2),
        display("id", "lastbox", new Box())
      );
      if (id) h.id = id;
      return h;
    }
  }
}
AddressingItems2.swf

Getting items by instance

layout.getLayoutItem(...args) works the same way with object instances.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package layout {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.*;
  import org.as3commons.ui.layout.shortcut.*;
  import flash.display.Sprite;

  public class AddressingItems3 extends Sprite {
    public function AddressingItems3() {
      var box : Box = new Box();
     
      var h : HGroup = hgroup(
        "gap", 1,
        Box.create(4),
        box,
        Box.create(5)
      );
     
      var d : Display = h.getLayoutItem(box) as Display;
      d.marginX = d.marginY = 20;

      h.layout(this);
    }
  }
}
AddressingItems3.swf

Configuring Individual Cells

A cell is considered to be any item added to a layout (sub layout or a display object). All layouts offer a possibility to setup size and alignment of individual or of groups of cells. You may specify properties for:

  • All cells of the layout
  • All cells of a particular row (vIndex)
  • All cells of a particular column (hIndex)
  • An individual cell at a specific position (vIndex, hIndex)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package layout {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.HLayout;
  import org.as3commons.ui.layout.shortcut.*;
  import flash.display.Sprite;

  public class CellConfig1 extends Sprite {
    public function CellConfig1() {
     
      var h : HLayout = hlayout(
        "maxItemsPerRow", 6,
        cellconfig("vIndex", 2, "marginY", 10),
        cellconfig("hIndex", 2, "marginX", 10),
        Box.create(24)
      );
      h.layout(this);
    }
  }
}
CellConfig1.swf

The same layout using the standard API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package layout {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.CellConfig;
  import org.as3commons.ui.layout.HLayout;
  import flash.display.Sprite;

  public class CellConfig2 extends Sprite {
    public function CellConfig2() {
      var h : HLayout = new HLayout();
      h.maxItemsPerRow = 6;
     
      var config : CellConfig = new CellConfig();
      config.marginY = 10;
      h.setCellConfig(config, -1, 2);
     
      config = new CellConfig();
      config.marginX = 10;
      h.setCellConfig(config, 2, -1);
     
      h.add(Box.create(24));
      h.layout(this);
    }
  }
}

CellConfig properties

width, height Explicit dimensions of the cell. If the content is larger than these dimensions it will overlap.
marginX, marginY The distance to the actual cell position (before margin was applied). Succeeding cells are affected and moved.
offsetX, offsetY A simple shift. The distance to the actual item position (before offset was applied). Succeeding items are not affected and not moved.
hAlign, vAlign Position of the content within the cell. Only applicable if explicit dimension have been set and are larger than the cell content. Always applicable with table layouts where explicit cell dimensions are calculated and set by definition.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package layout {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.HLayout;
  import org.as3commons.ui.layout.constants.Align;
  import org.as3commons.ui.layout.shortcut.*;
  import flash.display.Sprite;

  public class CellConfig3 extends Sprite {
    public function CellConfig3() {
     
      var h : HLayout = hlayout(
        "maxContentWidth", 150,
        cellconfig(
          "hIndex", 2, "vIndex", 1,
          "height", 60,
          "vAlign", Align.BOTTOM
        ),
        cellconfig(
          "vIndex", 2,
          "width", 60, "height", 60,
          "hAlign", Align.RIGHT
        ),
        cellconfig(
          "hIndex", 2, "vIndex", 3,
          "marginY", -30
        ),
        Box.create(22)
      );
      h.layout(this);
    }
  }
}
CellConfig3.swf

Excluding / Including Items

To reflect different states of an application, items in layouts can be (temporarily) excluded and later included again. They keep their logical position in any case. The following example probably shows more than a documentation may write.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package layout {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.*;
  import org.as3commons.ui.layout.shortcut.*;
  import flash.display.Sprite;
  import flash.events.MouseEvent;
  import flash.geom.Rectangle;

  public class Exclude extends Sprite {
    private var _top : VGroup;
    private var _bottom : HLayout;

    public function Exclude() {
      _top = vgroup(
        "offsetX", 10, "offsetY", 10,
        "gap", 10,
        h1, h1
      );
      _bottom = hlayout(
        "offsetX", 10, "offsetY", 170,
        "maxItemsPerRow", 9
      );
      layout();

      addEventListener(MouseEvent.CLICK, clickHandler);
    }

    private function get h1() : HGroup { // 4 box grids in a line
      return hgroup("gap", 10, h2, h2, h2, h2);
    }
   
    private function get h2() : HLayout { // 2x2 box grid
      return hlayout("maxItemsPerRow", 2, Box.create(4));
    }

    private function clickHandler(event : MouseEvent) : void {
      var box : Box = event.target as Box;
      if (_bottom.getLayoutItem(box) == null) {
        _top.getLayoutItem(box).excludeFromLayout(false);
        _bottom.add(box);
      } else {
        _bottom.remove(box);
        _top.getLayoutItem(box).includeInLayout();
      }
      layout();
    }
   
    private function layout() : void {
      _top.layout(this);
      _bottom.layout(this);

      graphics.clear();
      drawRect(_top.visibleRect);
      drawRect(_bottom.visibleRect);
    }

    private function drawRect(rect : Rectangle) : void {
      if (rect.width) rect.inflate(10, 10);
      with (graphics) {
        beginFill(0x333333);
        drawRect(rect.x, rect.y, rect.width, rect.height);
      }
    }
  }
}

Click a box in order to exclude it from or include it into the layout:

Exclude.swf

Nesting Layouts

Layouts supports unlimited nested layouts. Creating nested layouts using the shortcut API is fun.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package layout {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.shortcut.*;
  import flash.display.Sprite;

  public class NestedLayouts extends Sprite {
    public function NestedLayouts() {
      hgroup(
        vlayout(
          new Box(), // 1
          new Box(), // 2
          hlayout(
            new Box(), // 3
            new Box() // 4
          )
        ),
        new Box(), // 5
        hlayout(
          vgroup(
            new Box(), // 6
            new Box(), // 7
            new Box() // 8
          ),
          new Box() // 9
        ),
        new Box() // 10
      ).layout(this);
    }
  }
}
NestedLayoutExample.swf

Applying Transitions

A particular layout operates on a single display object in at least one of three cases.

  1. During the actual layout operation, the layout updates x and y properties of the object.
  2. If the object was configured to be excluded from the layout (or one of its containing layouts did so), the layout sets the visible properties of the object to false.
  3. If the object was configured to be included again into the layout (or one of its containing layouts did so), the layout sets the visible properties of the object to true. This is always followed by step 1 of this list.

This default behavior can be overridden by specifying custom event callbacks. If a custom callback is specified, the layout does not change object properties and instead invokes the callback.

The next example shows all of these three callbacks and their mandatory arguments.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package layout {
  import layout.common.box.Box;
  import com.gskinner.motion.GTween;
  import com.gskinner.motion.easing.Sine;
  import org.as3commons.ui.layout.HGroup;
  import org.as3commons.ui.layout.shortcut.*;
  import flash.display.DisplayObject;
  import flash.utils.Dictionary;

  public class Transitions extends ControlPanelBase {
    private var _layout : HGroup;
    private var _tweens : Dictionary;
   
    public function Transitions() {
      _tweens = new Dictionary();
     
      _layout = hgroup(
        "gap", 20,
        vgroup(
          "gap", 5,
          hgroup(
            Box.create(6)
          ),
          hgroup(
            "id", "row2",
            Box.create(6)
          ),
          hgroup(
            "id", "row3",
            Box.create(6)
          )
        ),
       
        checkBox({
          label: "show",
          selectedlabel: "hide",
          selected: true,
          change: includeExclude
        })
      );
      _layout.layout(this);
     
      _layout.getLayoutItem("row2").showCallback = showRow2;
      _layout.getLayoutItem("row2").hideCallback = hideRow2;
    }
   
    private function includeExclude(selected : Boolean) : void {
      if (selected) {
        _layout.getLayoutItem("row2").includeInLayout();
        _layout.getLayoutItem("row3").renderCallback = row3MoveDown;
      } else {
        _layout.getLayoutItem("row2").excludeFromLayout();
        _layout.getLayoutItem("row3").renderCallback = row3MoveUp;
      }
      _layout.layout(this);
    }
   
    private function hideRow2(o : DisplayObject) : void {
      tween(o, {alpha: 0});
    }

    private function showRow2(o : DisplayObject) : void {
      tween(o, {alpha: 1}, .3);
    }

    private function row3MoveDown(o : DisplayObject, x : int, y : int) : void {
      tween(o, {"x": x, "y": y});
    }

    private function row3MoveUp(o : DisplayObject, x : int, y : int) : void {
      tween(o, {"x": x, "y": y}, .3);
    }

    private function tween(o : DisplayObject, v : Object, d : Number = 0) : void {
      var tween : GTween = getTween(o);
      tween.delay = d;
      tween.setValues(v);
    }

    private function getTween(o : DisplayObject) : GTween {
      var tween : GTween = _tweens[o];
      if (!tween) {
        tween = new GTween();
        tween.ease = Sine.easeOut;
        tween.target = o;
        tween.duration = .2;
        tween.onComplete = function(tween : GTween) : void {
          delete _tweens[tween.target];
        };
        _tweens[o] = tween;
      }
      return tween;
    }

  }
}
Transitions.swf

Relayouting

Generally to refresh a layout (nested or not) you simply call its layout(container) method. This sets the entire content to the right position. However, in some cases a full reset of a nested layout is not necessary – e.g. when only a sub part has changed without affecting the outher arrangement. In this case we can relayout only the particular sub layout by calling layout(container, true).
Setting the relayout flag to true orders the layout to respect its position resulting from the last layouting process.

A common application for relayouts are contextual formulars.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package layout {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.framework.*;
  import org.as3commons.ui.layout.shortcut.*;

  public class Relayout extends ControlPanelBase {
    private var _layout : ILayout;

    public function Relayout() {
      _layout = vgroup(
        new Box(),

        hgroup(
          "id", "nested",
          Box.create(2),
          display(
            "id", "box",
            "inLayout", false,
            new Box()
          )
        ),

        new Box(),

        display(
          "marginY", 20,
          labelbutton({
            toggle: true,
            label: "include",
            selectedlabel: "exclude",
            change: buttonClick
          })
        )
      );
     
      _layout.layout(this);
    }
   
    private function buttonClick(selected : Boolean) : void {
      var boxDisplay : IDisplay = _layout.getLayoutItem("box") as IDisplay;
      if (selected) {
        boxDisplay.includeInLayout();
      } else {
        boxDisplay.excludeFromLayout();
      }
      var nested : ILayout = _layout.getLayoutItem("nested") as ILayout;
      nested.layout(this, true);
    }

  }
}
Relayout.swf

Layout Debugger

Layouts comes with a small debugging tool that visualises the structure of the given layout. The debugger is itself a display object and should be put on top of the layout at the same position.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package layout {
  import layout.common.box.Box;
  import org.as3commons.ui.layout.Table;
  import org.as3commons.ui.layout.constants.Align;
  import org.as3commons.ui.layout.debugger.LayoutDebugger;
  import org.as3commons.ui.layout.shortcut.*;
  import flash.display.Sprite;

  public class LayoutDebuggerTest extends Sprite {
    public function LayoutDebuggerTest() {
      var t : Table = table(
        "numColumns", 10,
        "hGap", 5, "vGap", 5,
        cellconfig(
          "hAlign", Align.CENTER, "vAlign", Align.MIDDLE
        ),
        Box.create(45, true, 20, 40)
      );
      t.layout(this);
     
      var debugger : LayoutDebugger = new LayoutDebugger();
      addChild(debugger);
      debugger.debug(t);
    }
  }
}

Moving the mouse over the layout displays the current layout structure on top. You can lock this structure by clicking onto the layout and vice versa unlock by clicking again:

LayoutDebuggerTest.swf

Layout Info

Each layout and layout item provides geometry data to be evaluated and further processed. You could apply borders or backgrounds or move other objects depending on these data. The layout debugger above takes highly use of it.

position The absolute position of the layout item regardless of margins or offset.
visibleRect The bounding rectangle of the layout’s visible content.
contentRect The bounding rectangle of the layout’s defined content. The content rect may be larger than the visible rect only if min dimensions are specified.

The visible rect of a layout cell is defined by the size of the cell content. The content rect of a layout cell is defined by the explicit size of the cell – specified using a cell config or automatically if the layout is a table layout.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package layout {
  import layout.common.box.Box;
  import org.as3commons.collections.framework.IIterator;
  import org.as3commons.ui.layout.Table;
  import org.as3commons.ui.layout.constants.Align;
  import org.as3commons.ui.layout.framework.IDisplay;
  import org.as3commons.ui.layout.shortcut.*;
  import flash.display.Sprite;
  import flash.geom.Rectangle;

  public class LayoutInfo extends Sprite {
    public function LayoutInfo() {
      var t : Table = table(
        "minWidth", 400, "minHeight", 200,
        "numColumns", 8,
        "hGap", 10, "vGap", 10,
        "hAlign", Align.CENTER, "vAlign", Align.MIDDLE,
        cellconfig(
          "hAlign", Align.CENTER, "vAlign", Align.MIDDLE
        ),
        Box.create(20, true, 20, 40)
      );
      t.layout(this);
     
      drawRect(this, t.contentRect, 0xCCCCCC, 0);
      drawRect(this, t.visibleRect, 0xFFFFFF, 0);
     
      var layer : Sprite = new Sprite();
      layer.alpha = .9;
      addChild(layer);

      var d : IDisplay;
      var iterator : IIterator = t.iterator();
      while (iterator.hasNext()) {
        d = iterator.next();
        drawRect(layer, d.contentRect, 0xFFFFFF, 0x666666);
        drawRect(layer, d.visibleRect, 0, 0xFF0000);
      }
    }

    private function drawRect(sprite : Sprite, rect : Rectangle, color : uint, border : uint) : void {
      with (sprite.graphics) {
        if (border) lineStyle(1, border);
        if (color) beginFill(color);
        drawRect(rect.x, rect.y, rect.width, rect.height);
        lineStyle(undefined);
        endFill();
      }
    }
  }
}
LayoutInfo.swf


28 Comments

  1. Layouts - Flashforum

    13. April 2011

    [...] [...]

  2. Bulent

    14. April 2011

    Hello,

    Good work, I have been looking forward for a good layout manager for so long. I will give this one a try asap.

    Cheers,

  3. mamxc

    15. April 2011

    Hi!
    Nice work. Some time ago I built a pure actionscript 3 open source layout framework, too. Here is a link which contains a demo: http://splink.posterous.com/actionscript-layout-framework-demo I’m looking forward to try yours and either switch or pull the best ideas into mine ;)
    Cheers,
    Max

  4. Jens Struwe

    15. April 2011

    Max, you are very welcome to contribute to the AS3Commons project: http://as3commons.org/ There are already projects that overlap with your splinklibrary (reflection, logging, utils). Contributing to AS3Commons has many benefits, a broader reception of your work, fast feebacks, code reviews, collective discussions … and, on the other side, a growing source base of professional ActionScript code.

  5. maxmc

    15. April 2011

    Hey Jens,
    thanks for the invitation, I will think about it.
    Cheers,
    Max

  6. Manisha

    19. April 2011

    Hi,
    I am trying to layout all the components in a container using HGroup but the content keeps flowing out. How do I ensure that content stays within the boundaries of the container ?

    -Thanks

  7. Jens Struwe

    19. April 2011

    Yes, this is one feature of this library, support within 20 minutes ;D

    You should use HLayout instead. This page describes:

    HGroup - Horizontal single line layout
    ...
    HLayout - Horizontal multi-line layout, row breaks on maxContentWidth and/or maxItemsPerRow, same as HGroup if neither specified

  8. Manisha

    19. April 2011

    Thanks Jens, I had tried HLayout. Maybe something foolish that I am doing. Please see this code:

    var qP:QM1 = new QM1();
    var goat:Goat_MC = new Goat_MC();
    var lion:Lion_MC = new Lion_MC();
    var monkey:Monkey_MC = new Monkey_MC();
    var tiger:Tiger_MC = new Tiger_MC();
    
    var layout:HLayout = new HLayout();//HGroup
    
    layout.add(goat);
    layout.add(lion);
    layout.add(monkey);
    layout.add(tiger);
    
    qP.x = 50;
    qP.y = 250;		
    layout.layout(qP);		
    
    addChild(qP);

    The content of qP flow were flowing outside from right then I tried various hAlign properties. Last I changed the registration point of qP to Left, now content flows out from Left :(

    -Thanks

  9. Jens Struwe

    19. April 2011

    Well, you need to specify a maximum condition where your rows should break. There are two appropriate properties you may use alternatively or also together:

    layout.maxContentWidth = 300;
    
    Or/And
    
    layout.maxItemsPerRow = 2;

    Edit: You may add your MCs at once:

    var layout : HLayout = new HLayout();
    layout.maxItemsPerRow = 2;
    layout.add(goat, lion, monkey, tiger);
    qP.x = 50;
    qP.y = 250;		
    layout.layout(qP);		
    addChild(qP);

    Edit2: You might find the shortcut API more readable:

    addChild(qP);
    var layout : HLayout = hlayout(
      "offsetX", 50, "offsetY", 250,
      "maxItemsPerRow", 2,
      goat, lion, monkey, tiger
    );
    layout.layout(qP);
  10. Manisha

    19. April 2011

    Tried layout.maxContentWidth = 300; Or/And
    layout.maxItemsPerRow = 2;

    My problem is the content flows out of the container. The only thing that had any effect was the registration point of Container. But keeping registration point center and left still did not allow content to be within the container.

    -Thanks

  11. Jens Struwe

    19. April 2011

    How is it to see your final SWF to get an imagination of your problem?

  12. Manisha

    19. April 2011

    Thanks Jens for helping out, here is the URL: http://funkyoinky.com/QuestionsPanel.swf

    -Thanks

  13. Manisha

    19. April 2011

    Have also put the .as file there, named: QuestionsPanel.as

    -Thanks

  14. Jens Struwe

    20. April 2011

    The .as file is not there, but I now see what your problem is. You don’t want the animals to be appearing in different rows. So HGroup was the right layout type. You want the animals starting right at the topleft corner of the container. I don’t know why they don’t, and I assume there is something your MCs. Try to debug the MC dimensions and see if they are really as big as they appear or if they have hidden space.

  15. bFunc

    4. Mai 2011

    for running those examples, please place link for download
    layout.common.box.Box;

  16. Jens Struwe

    4. Mai 2011

    Just created a new branch containing the examples: https://github.com/AS3Commons/as3commons-ui/tree/examples You can switch to the examples branch using checkout examples.

    The examples are now part of the master branch.

  17. bFunc

    6. Mai 2011

    Everything works fine, tnx. Classes are very useful, thanks a lot, again

  18. bFunc

    14. Mai 2011

    Hi, what is the most efficient way to clean up layout?
    I mean, at once remove all display children inside it, with weak listners attached. and layout instance itself?

    description of problem:
    I am drawing big amount of pages with nested layouts.
    element in Layout could be a Sprite that contains another layout with number of elements, depth is not limited, and I can’t attach elements form different child levels to one parent layout.

    Elements could be added or removed realtime. Update event generated than. Every update I redraw whole page from scratch, with new list of elements and parameters.

    It take huge amount of memory, after 3-5 seconds garbage collector sweeps removed sprites, and memory usage falls. but not to initial level.. something (about 1/3) still remains in memory.

  19. Jens Struwe

    14. Mai 2011

    Interesting question. The layout stores its display objects and sublayouts in the key of a Dictionary. Removing your component from the stage removes its layout references. The layout hence does not have any pointers and gets garbage collected. The same should be with its Dictionary. There are no event registrations or any global variables that could keep listening to the display objects.

  20. bFunc

    17. Mai 2011

    Thank you for your help. I will research this issue.

  21. Jens Struwe

    15. Juni 2011

    Here is a memory usage test: Layouts memory usage

    The test basically says that if you remove a layout reference from your code, the layout and all its data will entirely be removed from the memory.

  22. Brian Fox

    24. Juni 2011

    Hi there,
    First thank you for such a great layout framework.
    Is there a way of adding an element to a HLayout at the begining, or re-ordering so that the new element is added at the start of the hLayout?
    Thanks.

  23. Jens Struwe

    24. Juni 2011

    Good idea. I have updated the sources to support your requirement. Please download the most recent snapshot.swc. AddFirst Example

  24. Brian Fox

    27. Juni 2011

    Jens, you are amazing!

    Thank you very much for the addFirst function.

  25. Matt

    13. Oktober 2011

    This layout library looks awesome. I love libraries like this… simple and to-the-point, without making any assumptions beyond their central task. However, I find the “XLayout” naming of the various layout types to be quite cryptic, marring an otherwise excellent-looking library.

    The problem is the current names (“group” and “layout”) don’t communicate anything specific about the end result of applying each type of layout. Likewise, the “h” and “v” prefixes only suggest “something” to do with orientation, but not exactly what.

    May I suggest the following more descriptive names:

    HGroup -> Row
    VGroup -> Column
    HLayout -> WrappedRows
    VLayout -> WrappedColumns

    Without fully understanding all your documentation and playing with the examples (which I did because the page looked so nice!) I would really have no idea what, exactly, an “HLayout” does. On the other hand, the functionality of something named “WrappedRows” is almost immediately obvious, and is directly evocative of the end result.

    PS: I didn’t mention the “Table” and “DynTable” types above because they seem sort of unnecessary. They are just “aliases” for specific HGroup functionality, no? Actually, I would suggest these layouts simply be removed to simplify the library.

    Edit by Jens Struwe: Moved and discussed on tenderapp.

  26. Matt

    13. Oktober 2011

    Feature request: How about creating some layout(s) that can influence the dimensions of the target display objects? These types of layouts would seem to be required for creating “stretchy” UIs.

    For example, a layout that will cause a display object to assume some calculated dimension (e.g., same width as parent, 1/3 the height some other object, etc.).

    Correct me if I’m wrong, but currently this library only seems to be able to lay things out with respect to the *current* dimensions of the display objects, and cannot not directly influence those dimensions.

    Edit by Jens Struwe: Moved and discussed on tenderapp.

  27. Matt

    13. Oktober 2011

    Feature request: Could you make the layout debugger display the “id” of each item? And perhaps indicate layout nesting depth with numbers and/or color?

    Edit by Jens Struwe: Moved and discussed on tenderapp.

  28. bFunc

    23. Oktober 2012

    Any chance to port this layout library to haxe/nme?

Leave a Comment

You have a question or have experienced an issue? Please post it in the forum: http://sibirjak.tenderapp.com/ in order to make the discussion available at a more central place.