Practical Layout Management in Flex (from Sponsor)

6 We love Flex, but we are not fans of the default layout management in Flex. Flex offers a number of layout containers like Box, Panel, etc. If you take a careful look at them, most of them are derived from BoxLayout - a simple sequential layout algorithm that lays out components either horizontally or vertically. I'll use an example to illustrates the consequences of such over simplistic (or naive if you like) design.

Let's pick a real example - Juniper credit card application:

image

For the sake of brevity, we ignore all other parts except the address area.

If you use Flex to design the form above, you need around six HBox/VBox to get it right. Six is a big number considering this tiny form, and Adobe recommends that "It is good practice to avoid deeply nested layouts when possible."

The Solution: borrow layout management from other languages/frameworks.

Port GridBagLayout to Flex

We managed to port Java's most flexible layout manager to Flex: GridBagLayout. The screenshots below demonstrate our implementation of the UI using GridBagLayout. The best part is that it loves changes - change the form size and its sexy remains. It's super fast too. 

gbc1 gbc2

Corresponding code:

<?xml version="1.0" encoding="utf-8"?>


    import mx.controls.Button;
    import mx.controls.ComboBox;
    import mx.controls.TextInput;
    import com.insprise.common.ui.layout.GridBagConstraints;
    import mx.controls.Label;

private function createAddressComponents():void {
  // Row 1.
  var labelTitle:Label = new Label();
  labelTitle.text = "Address";
  labelTitle.setStyle("fontSize", 16);
  container.addComponent(labelTitle, new GridBagConstraints(0, 0, GridBagConstraints.REMAINDER, 1));
  // Row 2
  var label:Label = new Label();
  label.text = "Street Address";
  container.addComponent(label, new GridBagConstraints(0, 1, 2, 1, 0, 0, GridBagConstraints.LEFT, GridBagConstraints.HORIZONTAL));
  label = new Label();
  label.text = "Apt. Number";
  container.addComponent(label, new GridBagConstraints(GridBagConstraints.RELATIVE, 1, GridBagConstraints.REMAINDER, 1));
  // Row 3
  var text:TextInput = new TextInput();
  var gbc:GridBagConstraints = new GridBagConstraints(0, 2, 2, 1, 1, 0, GridBagConstraints.LEFT, GridBagConstraints.BOTH);
  gbc.insetRight = 10;
  container.addComponent(text, gbc);
  text = new TextInput();
  text.minWidth = 100;
  container.addComponent(text, new GridBagConstraints(GridBagConstraints.RELATIVE, 2, GridBagConstraints.REMAINDER, 1));
  // Row 4
  label = new Label();
  label.text = "City";
  container.addComponent(label, new GridBagConstraints(0, 3, 1, 1));
  label = new Label();
  label.text = "State";
  container.addComponent(label, new GridBagConstraints(1, 3, 1, 1));
  label = new Label();
  label.text = "Zip code";
  container.addComponent(label, new GridBagConstraints(2, 3, GridBagConstraints.REMAINDER, 1));
  // Row 5
  text = new TextInput();
  gbc = new GridBagConstraints(0, 4, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL);
  gbc.insetRight = 10;
  container.addComponent(text, gbc);
  var combo:ComboBox = new ComboBox();
  combo.width = 70; combo.minWidth = 70;
  gbc = new GridBagConstraints(GridBagConstraints.RELATIVE, 4, 1, 1);
  gbc.insetRight = 10;
  container.addComponent(combo, gbc);
  text = new TextInput();
  text.width = 40; text.minWidth=40;
  container.addComponent(text, new GridBagConstraints(GridBagConstraints.RELATIVE, 4, 1, 1, 0, 0, GridBagConstraints.LEFT, GridBagConstraints.NONE));
  label = new Label();
  label.text = "-"; label.width=10; label.minWidth=10;
  container.addComponent(label, new GridBagConstraints(GridBagConstraints.RELATIVE, 4, 1, 1, 0, 0, GridBagConstraints.LEFT, GridBagConstraints.NONE));
  text = new TextInput();
  text.width = 40; text.minWidth=40;
  container.addComponent(text, new GridBagConstraints(GridBagConstraints.RELATIVE, 4, 1, 1, 0.1, 0, GridBagConstraints.LEFT, GridBagConstraints.HORIZONTAL));
  // button
  var button:Button = new Button();
  button.label = "Submit"; button.minWidth=80;
  gbc = new GridBagConstraints(0, GridBagConstraints.RELATIVE, GridBagConstraints.REMAINDER, 1, 1.0, 1.0, GridBagConstraints.TOP, GridBagConstraints.NONE);
  gbc.insetTop = 15;
  container.addComponent(button, gbc);
}


  
  

Align Components Using Baseline

// Container 2.
label = new Label();
label.text = "Input prompt: ";
gbc = new GridBagConstraints(0, 0, 1, 1);
gbc.insetBottom = 12;
container2.addComponent(label, gbc);
text = new TextInput();
text.setStyle("fontSize", 20);
text.text = "Input value.";
gbc = new GridBagConstraints(1, 0, 1, 1);
gbc.insetBottom = 12;
container2.addComponent(text, gbc);

label = new Label();
label.text = "Input prompt: ";
container2.addComponent(label, new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.BASELINE_LEADING));
text = new TextInput();
text.text = "Input value.";
text.setStyle("fontSize", 20);
container2.addComponent(text, new GridBagConstraints(1, 1, 1, 1, 0, 0, GridBagConstraints.BASELINE_LEADING));

Result:

gbcbaseline 

With GridBagConstraints.BASELIINE_LEADING, you can easily create polished UI.

 

Availability

Porting GridBagLayout to Flex requires major effort - code copying never works as ActionScript AS3 and Java differ in fundamental details and their UI mechanisms vary in many tricky places.

We offer this package as a commercial package. Site license with full source code costs USD 2,498 only; update and support subscription is at USD 998 per year. To order, please contact sales@insprise.com (please use your corporate email account; free email addresses could be blocked; thanks).