Getting Started

Invoking Native Code

Include in Your Project

NativeObject

Platform-Specific

Real-World Examples

Using Native UI

Docking

Overlaying

Fullscreen

Widget

Floating

Navigation

Styling Native Controls

Working with Images

Native UI Layout

Panels

Properties

Writing Platform-Specific Code

Security

UI Framework Reference

Layout Panels

Controls

Ace

Platform Helpers

NativeObject

Examples

Troubleshooting Errors

Native UI Layout

SUMMARY
  • Layout refers to the placement and sizing of UI elements.
  • HTML content can use normal HTML layout (div, table, etc.).
  • Native content can take advantage of layout panels and layout properties from either XAML or JavaScript.
  • The current built-in layout panels are Canvas, StackPanel, and Grid.


For the HTML in your app, you use the same HTML/CSS layout mechanisms as you’ve always used. However, this topic discusses how you apply layout to native controls. The two main concepts are layout panels and layout properties.

Layout Panels

There are currently three cross-platform panels available:

  • Canvas for absolute positioning
  • StackPanel for horizontal or vertical stacking
  • Grid for complex layout

Canvas

In a Canvas, you position children with explicit Left and/or Top coordinates. Each child renders at its natural size by default.

In XAML, you set these coordinates as “attached properties,” e.g.:

<Canvas>
    <!-- The default position is 0,0: -->
    <Button                                    Background="Red"    />
    <Button Canvas.Left="100"                  Background="Orange" />
    <Button                   Canvas.Top="150" Background="Yellow" />
    <Button Canvas.Left="150" Canvas.Top="200" Background="Green"  />
</Canvas>

In JavaScript, you set the coordinates via static methods on Canvas to get the same results:

var canvas = new ace.Canvas();

var b1 = new ace.Button();
b1.setBackground("Red");
canvas.getChildren().add(b1);
    
var b2 = new ace.Button();
b2.setBackground("Orange");
ace.Canvas.setLeft(b2, 100);
canvas.getChildren().add(b2);

var b3 = new ace.Button();
b3.setBackground("Yellow");
ace.Canvas.setTop(b3, 150);
canvas.getChildren().add(b3);

var b4 = new ace.Button();
b4.setBackground("Green");
ace.Canvas.setLeft(b4, 150);
ace.Canvas.setTop(b4, 200);
canvas.getChildren().add(b4);

// Navigate to this Canvas
ace.navigate(canvas);

Here is the result of using either approach, shown on iOS:

And here it is on Android:

The different default Button size on each platform makes the results look a bit different from each other, but you could always explicitly set each Button’s Width and Height properties if the exact sizes matter.

StackPanel

StackPanel doesn’t provide any attached properties for controlling the layout of its children. You just add children, and they get stacked (vertically by default). You can set StackPanel’s Orientation property to either “vertical” or “horizontal”.

By default, children are given their natural size in the direction of stacking, and they are stretched to fill the perpendicular direction. You can change this with the HorizontalAlignment/VerticalAlignment properties discussed later in this topic.

Here’s a simple vertical StackPanel defined in XAML:

<StackPanel>
    <Button Background="Red"    />
    <Button Background="Orange" />
    <Button Background="Yellow" />
    <Button Background="Green"  />
</StackPanel>

And here it is defined in JavaScript:

var stackPanel = new ace.StackPanel();

var b1 = new ace.Button();
b1.setBackground("Red");
stackPanel.getChildren().add(b1);
    
var b2 = new ace.Button();
b2.setBackground("Orange");
stackPanel.getChildren().add(b2);

var b3 = new ace.Button();
b3.setBackground("Yellow");
stackPanel.getChildren().add(b3);

var b4 = new ace.Button();
b4.setBackground("Green");
stackPanel.getChildren().add(b4);

// Navigate to this StackPanel
ace.navigate(stackPanel);

Vertical StackPanel (Android)

Vertical StackPanel (iOS)

(Unlike on iOS, Android buttons render with a small amount of built-in margin, rounded corners, and a shadow.)

To make it stack horizontally, add the following property in XAML:

<StackPanel Orientation="Horizontal">
    <Button Background="Red"    />
    <Button Background="Orange" />
    <Button Background="Yellow" />
    <Button Background="Green"  />
</StackPanel>

or in JavaScript:

var stackPanel = new ace.StackPanel();
stackPanel.setOrientation("Horizontal");
...

Horizontal StackPanel (Android)

Horizontal StackPanel (iOS)

Grid

Grid enables you to define rows and columns, then place each child in specific rows/columns. There are many options for configuring how rows and columns are sized. They can be auto-sized, given explicit sizes, or given proportional sizes. For now, you can find more documentation about this toward the bottom of this page.

Here’s an example that uses a Grid in XAML:

<Grid>
    <!-- Define a 3x3 grid with a center cell twice the size -->
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition Height="2*" />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition Width="2*" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>

    <!-- Row 0 -->
    <Button                                     Background="Red"       />
    <Button                     Grid.Column="1" Background="Orange"    />
    <Button                     Grid.Column="2" Background="Yellow"    />
    <!-- Row 1 -->
    <Button        Grid.Row="1"                 Background="Green"     />
    <Button        Grid.Row="1" Grid.Column="1" Background="Aqua"      />
    <Button        Grid.Row="1" Grid.Column="2" Background="SteelBlue" />
    <!-- Row 2 -->
    <Button        Grid.Row="2"                 Background="Purple"    />
    <Button        Grid.Row="2" Grid.Column="1" Background="Brown"     />
    <Button        Grid.Row="2" Grid.Column="2" Background="Gray"      />
</Grid>

If you navigate to this markup file, you get the following result, which stretches to fill the screen regardless of size/orientation:

Simple Grid (Android)

Simple Grid (iOS)

Here’s the same example purely in JavaScript, which produces the identical result with no markup involved:

var grid = new ace.Grid();

grid.getRowDefinitions().add(new ace.RowDefinition());
grid.getRowDefinitions().add(new ace.RowDefinition("2*"));
grid.getRowDefinitions().add(new ace.RowDefinition());

grid.getColumnDefinitions().add(new ace.ColumnDefinition());
grid.getColumnDefinitions().add(new ace.ColumnDefinition("2*"));
grid.getColumnDefinitions().add(new ace.ColumnDefinition());

var b1 = new ace.Button();
b1.setBackground("Red");
grid.getChildren().add(b1);

var b2 = new ace.Button();
ace.Grid.setColumn(b2, 1);
b2.setBackground("Orange");
grid.getChildren().add(b2);

var b3 = new ace.Button();
ace.Grid.setColumn(b3, 2);
b3.setBackground("Yellow");
grid.getChildren().add(b3);

var b4 = new ace.Button();
ace.Grid.setRow(b4, 1);
b4.setBackground("Green");
grid.getChildren().add(b4);

var b5 = new ace.Button();
ace.Grid.setRow(b5, 1);
ace.Grid.setColumn(b5, 1);
b5.setBackground("Aqua");
grid.getChildren().add(b5);

var b6 = new ace.Button();
ace.Grid.setRow(b6, 1);
ace.Grid.setColumn(b6, 2);
b6.setBackground("SteelBlue");
grid.getChildren().add(b6);

var b7 = new ace.Button();
ace.Grid.setRow(b7, 2);
b7.setBackground("Purple");
grid.getChildren().add(b7);

var b8 = new ace.Button();
ace.Grid.setRow(b8, 2);
ace.Grid.setColumn(b8, 1);
b8.setBackground("Brown");
grid.getChildren().add(b8);

var b9 = new ace.Button();
ace.Grid.setRow(b9, 2);
ace.Grid.setColumn(b9, 2);
b9.setBackground("Gray");
grid.getChildren().add(b9);

// Navigate to the Grid
ace.navigate(grid);

Children can span multiple rows/columns with the Grid.RowSpan and Grid.ColumnSpan properties, whose default value is 1. The following Grid produces the result below:

<Grid>
    <!-- Define a 3x3 grid with a center cell twice the size -->
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition Height="2*" />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition Width="2*" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>

    <!-- Row 0 -->
    <Button        Grid.ColumnSpan="2"                              Background="Red"       />
    <Button                                         Grid.Column="2" Background="Yellow"    />
    <!-- Row 1 -->
    <Button                            Grid.Row="1"                 Background="Green"     />
    <Button                            Grid.Row="1" Grid.Column="1" Background="Aqua"      />
    <Button        Grid.RowSpan="2"    Grid.Row="1" Grid.Column="2" Background="SteelBlue" />
    <!-- Row 2 -->
    <Button                            Grid.Row="2"                 Background="Purple"    />
    <Button                            Grid.Row="2" Grid.Column="1" Background="Brown"     />
</Grid>

Grid with RowSpan, ColumnSpan (Android)

Grid with RowSpan, ColumnSpan (iOS)

In JavaScript, you can set these properties as follows:

...
ace.Grid.setColumnSpan(b1, 2);
...
ace.Grid.setRowSpan(b6, 2);
...

Layout Properties

Besides panel-specific properties that can be attached to any UI object (like Canvas.Top or Grid.Row), all UI objects can be marked with properties that affect layout, such as Margin. Here’s a description of each one:

Margin

Can be set to a “thickness” value, which is one, two, or four comma-delimited numbers. For example:

  • A Margin of 20 adds a 20-unit margin around all four sides
  • A Margin of “20,10” adds a 20-unit margin to the left and right sides, and a 10-unit margin to the top and bottom sides
  • A Margin of “10,20,30,40” adds different margin values to the left, top, right, and bottom sides, in that order.

Padding

Padding is an “inner margin” that is only supported on specific controls, such as Button. The Grid and StackPanel layout panels also support padding.

Padding can be set to a “thickness” value, just like with Margin.

Width and Height

All UI elements can be given explicit widths and heights, which override their natural size.

HorizontalAlignment and VerticalAlignment

If a layout panel gives a child element more space than it needs, you can use these properties to customize how the child element fills that space.

HorizontalAlignment can be set to Left, Right, Center, or Stretch

VerticalAlignment can be set to Top, Bottom, Center, or Stretch

In a Grid, each element is stretched both horizontally and vertically by default in order to fill the “cell” given to it. The image below demonstrates what happens if each Button in the earlier Grid example (the one leveraging RowSpan and ColumnSpan) is marked with either the following in XAML:

<Button ... HorizontalAlignment="Right" VerticalAlignment="Bottom" />

or the following in JavaScript:

...
b1.setHorizontalAlignment("Right");
b1.setVerticalAlignment("Bottom");
...

Examples are also given with values of “Left” and “Top” as well as “Center” and “Center”.

The original Button layout is shown faded in the background just to make the cell sizes more obvious. In reality, the smaller buttons, now given their natural non-stretched size, are on top of a plain white background.

HorizontalAlignment=Right, VerticalAlignment=Bottom (Android)

HorizontalAlignment=Left, VerticalAlignment=Top (Android)

HorizontalAlignment=Center, VerticalAlignment=Center (iOS)

In a StackPanel, alignment only has an impact in the direction that is perpendicular to stacking, because children are given the exact amount of space they need in the direction of stacking. No more, no less. Here’s an example that uses different values of HorizontalAlignment in a vertical StackPanel:

<StackPanel>
    <Button HorizontalAlignment="Left"    Foreground="White" Background="Red" />
    <Button HorizontalAlignment="Right"   Background="Orange" />
    <Button HorizontalAlignment="Center"  Background="Yellow" />
    <Button HorizontalAlignment="Stretch" Foreground="White" Background="Green" />
</StackPanel>

HorizontalAlignment in a Vertical StackPanel (iOS)

And here’s an example that uses different values of VerticalAlignment in a horizontal StackPanel:

<StackPanel Orientation="Horizontal">
    <Button VerticalAlignment="Top"     Foreground="White" Background="Red" />
    <Button VerticalAlignment="Bottom"  Background="Orange" />
    <Button VerticalAlignment="Center"  Background="Yellow" />
    <Button VerticalAlignment="Stretch" Foreground="White" Background="Green" />
</StackPanel>

VerticalAlignment in a Horizontal StackPanel (iOS)

HorizontalContentAlignment and VerticalContentAlignment

These two properties can be set on some controls, such as TextBlock and Button, to control the alignment of its inner content. They accept the same values as HorizontalAlignment and VerticalAlignment.