Flex 3:Feature Introductions: Enhanced Constraints
From Adobe Labs
The new SDK feature, Enhanced Constraints, builds upon the existing constraint-based layout mechanism which is available in containers that allow absolute positioning (Canvas, Panel, Module and Application). Enhanced Constraints allow users to create complex, resizable layouts by partitioning absolute positioning containers with ConstraintColumns and ConstraintRows and constraining child controls to those column and row boundaries. This gives developers the ability to define sibling-relative constraints whereas in Flex 2.0 developers could only define parent-child constraints.
ConstraintColumns and ConstraintRows are non-UI objects added to an absolute positioning container, like a Canvas, that divides up the container’s space. Controls in a Canvas can have constraint styles set on them where those constraints are evaluated relative to the parent edges, as was the behavior in Flex 2.0, or relative to ConstraintColumn and ConstraintRow boundaries which is new behavior in Moxie. ConstraintColumns and ConstraintRows have three sizing options available to them.
1. A ConstraintColumn/ConstraintRow can be fixed size, meaning it consumes a fixed pixel size of the parent container. This can be indicated like so:
<mx:ConstraintColumn id=”col1” width=”100” />
This means as the parent container grows or shrinks, the ConstraintColumn always remains 100 pixels wide.
2. A ConstraintColumn/ConstraintRow can be percentage sized, meaning it consumes a percentage of the parent container’s available space. This can be indicated like so:
<mx:ConstraintColumn id=”col1” width=”80%” />
This means as the parent container grows or shrinks, the ConstraintColumn always takes up 80% of the total container’s width.
3. A ConstraintColumn/ConstraintRow can be content size, meaning it sizes itself to the controls constrained within its boundaries. This can be indicated by leaving off a width property from the tag.
<mx:ConstraintColumn id=”col1” />
This means the width of this ConstraintColumn is determined by the width of its largest child. When children span multiple content sized ConstraintColumns or ConstraintRows, an algorithm is used to divvy up the space consumed by the children to the content-sized columns and rows.
Additionally, you can specify minimum and maximum sizes to control how much your ConstraintColumns/ConstraintRows grow and shrink. Minimums and maximums apply only to "stretchy" ConstraintColumns/ConstraintRows, ie: percentage and content size columns/rows.
Constraint styles can be set on controls relative to the parent container edges or relative to a ConstraintColumn or ConstraintRow boundary. The left, right, and horizontalCenter constraint styles can be set relative to the parent container’s left and right edges or they can be set relative to any ConstraintColumn. The top, bottom, and verticalCenter constraint styles can be set relative to the parent container’s top and bottom edges or they can be set relative to any ConstraintRow. Constraint styles can take a number which indicates the offset relative to the parent edge, or a constraint expression which defines which ConstraintColumn/ConstraintRow boundary the offset is evaluated from. Notice that when setting constraints relative to a ConstraintColumn or ConstraintRow, the id of that column/row is referenced in the constraint expression.
For example, the following markup indicates a Button placed 10 pixels from the left edge of the parent container.
<mx:Button id="btn" left="10"/>
Whereas the markup below indicates a Button placed 10 pixels from the left edge of the ConstraintColumn with id="col1".
<mx:Button id="btn" left="col1:10"/>
The Enhanced Constraints feature provides similar functionality to the Grid container. For the Moxie release, the Grid container will be deprecated and users will be encouraged to use Enhanced Constraints to build resizable layouts.
What is the FlexBuilder support for this feature?
For the Moxie release, this feature will be tightly integrated into FlexBuilder’s Design View. This work has not been completed for the Beta release though a sneak peek at the FlexBuilder UI is included <a href="#Sneak">below</a>. Users are limited to hand coding Enhanced Constraint layouts in the Beta 1 release. The Beta 1 release of FlexBuilder will offer code hinting for the new constraint syntax.
What was the impetus for this feature?
Great question! The goal of this feature is to build resizable layouts. Sure, this is already possible (and very easy to do) with the relative layout containers like HBox, VBox, Form, Tile, etc. However, when using any of the absolute positioning containers (Canvas, Application, Module and Panel) for pixel-perfect positioning of child controls, making the layout resizable is much more onerous. In Flex 2, designers and developers could use the constraint styles to constrain children to the parenting container's borders and build limited reflowing capabilities into their layouts. It was much more difficult to get robust reflowing capabilities or to express sibling relative constraints in absolute positioning containers. Users would have had to use data-binding expressions when setting constraint values in order to get the constraints to take other child controls into consideration or would have had to use nested containers. So....we introduced ConstraintColumns and ConstraintRows that can grow and shrink as the application is resized or that can be fixed in size (to mimic gutter behavior). By adding ConstraintColumns and ConstraintRows, we now allow users to constrain to boundaries within the absolute positioning container in addition to the parent edges. So, the key take away from this story is: build resizable layouts in your absolute positioning containers! It is now easy to do from an implementation standpoint and your end users will appreciate it (scrolling around an application can get very tiresome, very quickly).
Sample Code:
First, lets walk through some very basic examples to get acquainted with the new constraints syntax. You can download the samples here.
sample1: In our first example, we show a Canvas with two ConstraintColumns with a fixed width of 100 pixels and two ConstraintRows with a fixed height of 100 pixels. The Canvas sizes itself to fit the ConstraintColumns and ConstraintRows (notice the width and height of the Canvas is 200 pixels). The Buttons are constrained to the ConstraintColumn and ConstraintRow boundaries. Take a look at the constraints set on the Buttons, they are a mixture of ConstraintColumn/ConstraintRow relative constraints as well as constraints set relative to the parent edges.
sample2: In this example, we show a percentage size Canvas with percentage size ConstraintColumns and ConstraintRows. The ConstraintColumns and ConstraintRows consume the specified percentage of the Canvas' available space and controls are constrained to them.
Play around with resizing the Canvas - notice how as you grow the Canvas the ConstraintColumns and ConstraintRows also grow in order to consume the specified percentage of the Canvas' space. As the Canvas shrinks, you'll get scrollbars as necessary to view all the content. The Buttons grow and shrink too, since they are constrained to the "stretchy" ConstraintColumns and ConstraintRows.
sample3: In this example we show a preferred size Canvas with content size ConstraintColumns and ConstraintRows. The ConstraintColumns and ConstraintRows size themselves to the content constrained within their boundaries. So, notice that Button A has the following constraints set on it:
<mx:Button label="Button A" left="col1:20" right="col1:0" width="100" top="row1:10" bottom="row1:10" height="100"/>
Which means that ConstraintColumn with id="col1" is sized large enough to hold the Button who's width is 100 pixels plus the 20 pixel left offset. So, notice that col1 has a width of 120 pixels. Similarly, the ConstraintRow with id="row1" will size itself large enough to hold the Button who's height is 100 pixels plus the 10 pixel top offset and the 10 pixel bottom offset. So, notice that row1 has a height of 120 pixels.
reflow: Now lets take a look at a slightly more advanced example. Here, we affix controls side by side by constraining them to ConstraintColumn/ConstraintRow boundaries. Run the swf and resize the application larger and smaller - notice how the Button and TextInput always stay a fixed distance apart from each other. Also, notice how the Text controls reflow with the application. This example also highlights how ConstraintColumns and ConstraintRows can be used to create fixed gutters in a container.
Known Issues:
- SDK-9612 Components that extend Button are a few pixels off when calculating their position according to the 'baseline' constraint style.
- SDK-9602 If the percentages allotted to ConstraintColumns/ConstraintRows are > 100%, the percentages are not adjusted to add up to 100%.
- SDK-9457 When the borderThickness of a Canvas is set and constraints are set on child controls, the Canvas sprouts an unnecessary scrollbar.
Sneak Peek of FlexBuilder Support:
We will be adding a very robust UI to FlexBuilder's Design View in order to author constraint-based layouts. Below we have a sneak peek at what is to come.
FlexBuilder's Design View will be augmented to show constraint affordances when authoring constraint-based layouts in absolute positioning containers. These affordances include header bars to display the sizing of a ConstraintColumn/ConstraintRow and to select a ConstraintColumn/ConstraintRow, runners which are contained within header bars and are used to create a ConstraintColumn/ConstraintRow, gridlines to visually indicate the delineation of ConstraintColumn/ConstraintRow, and constraint lines and constraint icons to visually indicate a constraint set on a control.
Here we have a screenshot of the Design View area with the header bars, runners and a gridline drawn. Users will use the headerbars to track where to create a gridline - mousing over the headerbar gives visual feedback regarding the dimensions of the ConstraintColumn being created.
Mousing down in the runner actually creates a gridline which results in 2 new ConstraintColumn instances.
Constraint icons decorate constrainable child controls. Clicking on a constraint icon pops up a popup menu that allows configuration of the constraint.
Here the button has had its horizontalCenter constraint style set via the popup menu and this is indicated with the stretchy constraint icon.
More to come in the next public drop of Moxie including support in the PropertyInspector to set/edit constraints, setting properties like id, width/height on ConstraintColumns/ConstraintRows and live updating when dragging constrained controls around in Design View.




