Layouts

The Cascades framework uses layouts to construct UIs. A layout provides the basic design for a container in your application. Cascades supports a variety of different layouts that you can use to arrange and position controls in your apps. You can stack controls horizontally or vertically, align controls to the top or sides of a container, and even place controls at specific positions on the screen.

Each layout has its own set of properties that determines how child controls are arranged in the layout (for example, whether controls should be arranged from left to right or from top to bottom). You can also specify layout properties for each child control to determine the position and relative size of the control. By using the right layouts in your applications, you can create a UI that looks great and scales easily even if the sizes of your UI components change.

Overview of the available layouts

Cascades provides four types of layouts. You can use as many layouts as you want in your apps, and you can also use layouts within other layouts (for example, a stack layout inside an absolute layout).

Absolute layout

AbsoluteLayout lets you specify exactly where controls should be located on the screen. You specify x and y coordinates (in pixels) for the location of the controls in their parent container.

This is an appropriate layout to use if you're creating a complicated UI that requires precise positioning of controls. You can also choose to use this layout if you're creating your app for a specific screen resolution. Keep in mind that while stack layouts and dock layouts make it easy to create a UI that's independent of screen resolution, this isn't necessarily the case with absolute layouts. When you use an absolute layout, your UI may not appear correctly if the containers in your app change in size or position, or if your app runs on a device with a different screen resolution.

Positioning

You can use AbsoluteLayoutProperties to specify the exact location of controls in your UI. The positionX and positionY properties provide the x and y coordinates for controls in the parent container. The image to the right shows three button positioned in an absolute layout.

Screen showing three Button controls arranged in an absolute layout.

Using an absolute layout in QML

The following code sample shows you how to specify the x and y coordinates on the three Button controls shown in the screen shot above in QML:

Container {
    layout: AbsoluteLayout {}
    // Create three buttons, and set the absolute
    // position for each
    Button {
        text: "Control 1"
        layoutProperties: AbsoluteLayoutProperties {
        positionX: 25
        positionY: 25
        }
    }
    Button {
        text: "Control 2"
        layoutProperties: AbsoluteLayoutProperties {
            positionX: 200
            positionY: 125
        }  
    }
    Button {
        text: "Control 3"
        layoutProperties: AbsoluteLayoutProperties {
            positionX: 350
            positionY: 225
        }
    }
}

Using an absolute layout in C++

The following code sample shows you how to specify the x and y coordinates on the three Button controls shown in the screen shot above in C++:

#include <bb/cascades/Container>
#include <bb/cascades/AbsoluteLayout>
#include <bb/cascades/AbsoluteLayoutProperties>
#include <bb/cascades/Button>

Container *absoluteContainer = Container::create();
 
AbsoluteLayoutProperties *aLPropertiesTop = 
        AbsoluteLayoutProperties::create().x(25).y(25);
 
AbsoluteLayoutProperties *aLPropertiesCenter = 
        AbsoluteLayoutProperties::create().x(200).y(125);
         
AbsoluteLayoutProperties *aLPropertiesBottom = 
        AbsoluteLayoutProperties::create().x(350).y(225);
 
// Create three buttons, and set the absolute position for each        
absoluteContainer->add(Button::create()
                       .text("Control 1")
                       .layoutProperties(aLPropertiesTop));
absoluteContainer->add(Button::create()
                       .text("Control 2")
                       .layoutProperties(aLPropertiesCenter));
absoluteContainer->add(Button::create()
                       .text("Control 3")
                       .layoutProperties(aLPropertiesBottom));

Stack layout

StackLayout is the default layout for containers in Cascades. It allows you to stack controls vertically or horizontally. You can specify properties that stack the controls in a particular direction (such as from left to right or from bottom to top), and you can set margins (empty space) between the controls.

You could use this layout if you want to arrange controls next to each other without specifying the precise position of each control. This layout also provides a lot of flexibility when adding and removing controls. When you remove a control from a stack layout, the surrounding controls are rearranged automatically to fill the empty space.

Orientation

You can use LayoutOrientation to specify the arrangement of controls in a StackLayout. A StackLayout supports a top-to-bottom orientation ( LayoutOrientation::TopToBottom) as well as a left-to-right orientation ( LayoutOrientation::LeftToRight). Additionally, a StackLayout supports a bottom-to-top oritentation ( LayoutOrientation::BottomToTop) as well as a right-to-left orientation ( LayoutOrientation::RightToLeft). The default orientation for a stack layout is top-to-bottom. The image to the right shows four buttons in a top-to-bottom orientation, with all four buttons aligned to the center using the horizontalAlignment property.

Screen showing four Button controls arranged in a stack layout.

Using a stack layout in QML

The following code sample shows you how to apply a top-to-bottom orientation on four buttons as shown in the screen shot above in QML:

Container {
    layout: StackLayout {}
 
    Button {
        text: "Control 1"
        layoutProperties: StackLayoutProperties {}
        horizontalAlignment: HorizontalAlignment.Center
    }
    Button {
        text: "Control 2"
        layoutProperties: StackLayoutProperties {}
        horizontalAlignment: HorizontalAlignment.Center
    }
    Button {
        text: "Control 3"
        layoutProperties: StackLayoutProperties {}
        horizontalAlignment: HorizontalAlignment.Center
    }
    Button {
        text: "Control 4"
        layoutProperties: StackLayoutProperties {}
        horizontalAlignment: HorizontalAlignment.Center
    }    
}

Using a stack layout in C++

The following code sample shows you how to apply a top-to-bottom orientation on four buttons as shown in the screen shot above in C++:

#include <bb/cascades/Container>
#include <bb/cascades/StackLayout>
#include <bb/cascades/StackLayoutProperties>
#include <bb/cascades/LayoutOrientation>
#include <bb/cascades/Button>

Container* pContainer = new Container();
StackLayout *pStackLayout = new StackLayout();
pStackLayout->setOrientation( LayoutOrientation::TopToBottom );
pContainer->setLayout(pStackLayout);
 
Button* pButton1 = Button::create().text("Control 1");
Button* pButton2 = Button::create().text("Control 2");
Button* pButton3 = Button::create().text("Control 3");
Button* pButton4 = Button::create().text("Control 4");
 
pButton1->setLayoutProperties( StackLayoutProperties::create()
        .horizontal( HorizontalAlignment::Center ) );
pButton2->setLayoutProperties( StackLayoutProperties::create()
        .horizontal( HorizontalAlignment::Center ) );
pButton3->setLayoutProperties( StackLayoutProperties::create()
        .horizontal( HorizontalAlignment::Center ) );
pButton4->setLayoutProperties( StackLayoutProperties::create()
        .horizontal( HorizontalAlignment::Center ) );
 
pContainer->add( pButton1 );
pContainer->add( pButton2 );
pContainer->add( pButton3 );
pContainer->add( pButton4 );

Using space quotas

You can specify the size of UI controls in several ways in your applications. A common way is to use the preferredWidth and preferredHeight properties to determine the size of a control. However, this approach might not work very well if the screen resolution changes or if you change the structure of your UI. Instead, you can direct UI controls to use as much space as is available in their parent container, as well as maintain sizes relative to each other, by using space quotas.

Space quotas apply only to controls in a stack layout and are set by using the spaceQuota child layout property. The spaceQuota property determines how much a control should expand or shrink to fill the available space in a layout. This property can have a negative or positive value:

  • A negative spaceQuota value indicates that the control uses as much space as necessary to appear correctly in the layout, but no more. The control won't expand or shrink to fill any available space in the layout. This is the default behavior if you don't specify a value for spaceQuota.
  • A positive spaceQuota value indicates that the control uses as much space as it can with respect to other controls in the same container, and expands and shrinks depending on the available space. The amount that the control expands or shrinks depends on the value of spaceQuota. A control with a space quota of 2 expands to use twice as much space as a control with a space quota of 1. Similarly, a control with a space quota of 2 shrinks twice as much as a control with a space quota of 1.

You can think of positive space quotas as forming a ratio that represents the relative sizes of the controls. A control with a space quota of 3 and a control with a space quota of 2 form a ratio of 3:2, and the sizes of the controls will always remain in that ratio. Space quotas of 3 and 2 are equivalent to space quotas of 6 and 4 (or 27 and 18) because the ratio is still 3:2.

The following image demonstrates how different space quotas determine the sizes of controls in a layout. Each row of buttons represents a container with a left-to-right stack layout, and the numbers on each button indicate the value of the button's spaceQuota property:


Diagram showing the use of the spaceQuota property on a series of Button controls.

In the image above, the last row of buttons contains a button with a negative space quota. When combined with controls that have positive space quotas, controls with negative space quotas take as much space as the control needs (the default height or width of the control). Any remaining space is divided between the controls with positive space quotas, depending on their specific space quota values.

The following code samples create a left-to-right stack layout, in QML, and add three buttons to the layout. Each button has a different space quota that determines its relative size.

Container {
    layout: StackLayout {
        orientation: LayoutOrientation.LeftToRight
    }
  
    Button {
        layoutProperties: StackLayoutProperties {
            spaceQuota: 1
        }
    }
  
    Button {
        layoutProperties: StackLayoutProperties {
            spaceQuota: 2
        }
    }
  
    Button {
        layoutProperties: StackLayoutProperties {
            spaceQuota: 3
        }
    }
}

Here's the same layout in C++:

// Create the container and layout
Container* myContainer = new Container;
StackLayout* layout = StackLayout::create()
                       .orientation(LayoutOrientation::LeftToRight);
myContainer->setLayout(layout);
  
// Create three sets of stack layout properties
StackLayoutProperties* slp1 = StackLayoutProperties::create()
                               .spaceQuota(1);
StackLayoutProperties* slp2 = StackLayoutProperties::create()
                               .spaceQuota(2);
StackLayoutProperties* slp3 = StackLayoutProperties::create()
                               .spaceQuota(3);
  
// Add buttons that use the stack layout properties
myContainer->add(Button::create().layoutProperties(slp1));
myContainer->add(Button::create().layoutProperties(slp2));
myContainer->add(Button::create().layoutProperties(slp3));

The code samples above both generate the following button arrangement:

Screen shot showing three button controls in a side-to-side stack layout.

Dock layout

DockLayout aligns controls to different positions in a container, such as the top, right, bottom, or left edge. You can also specify that a control should fill the available width or height of the container.

This layout is a good choice if you want to specify the positions of controls in relation to other controls and the overall UI. For example, a control that's aligned to the top of its parent container always remains at the top, even if the size or position of the parent container changes or if you rescale your UI.

Alignment

You can use HorizontalAlignment and VerticalAlignment to specify the position of controls in a parent container. The image to the right shows three buttons arranged using a DockLayout.

The button labeled Control 1 uses HorizontalAlignment.Left and VerticalAlignment.Center for its horizontal and vertical alignment, respectively. The button labeled Control 2 uses HorizontalAlignment.Right and VerticalAlignment.Top, and Control 3 uses HorizontalAlignment.Center and VerticalAlignment.Bottom to align the button.

Screen showing three Button controls arranged in a dock layout.

Using a dock layout in QML

The following code sample shows you how to specify the alignment of three Button controls as shown in the screen shot above in QML:

Container {
    layout: DockLayout {}
   
    Button {
        text: "Control 1"
        horizontalAlignment: HorizontalAlignment.Left
        verticalAlignment: VerticalAlignment.Center                
    }
   
    Button {
        text: "Control 2"
        horizontalAlignment: HorizontalAlignment.Right
        verticalAlignment: VerticalAlignment.Top
    }
    Button {
        text: "Control 3"
        horizontalAlignment: HorizontalAlignment.Center
        verticalAlignment: VerticalAlignment.Bottom
    }      
}

Using a dock layout in C++

The following code sample shows you how to specify the alignment of three Button controls as shown in the screen shot above in C++:

#include <bb/cascades/Container>
#include <bb/cascades/DockLayout>
#include <bb/cascades/VerticalAlignment>
#include <bb/cascades/HorizontalAlignment>
#include <bb/cascades/Button>

Container* pContainer = new Container();
DockLayout *pDockLayout = new DockLayout();
pContainer->setLayout(pDockLayout);

Button* pButton1 = Button::create().text("Control 1");
 
pButton1->setHorizontalAlignment(HorizontalAlignment::Left);
pButton1->setVerticalAlignment(VerticalAlignment::Center);

Button* pButton2 = Button::create().text("Control 2");
 
pButton2->setHorizontalAlignment(HorizontalAlignment::Right);
pButton2->setVerticalAlignment(VerticalAlignment::Top);

Button* pButton3 = Button::create().text("Control 3");
 
pButton2->setHorizontalAlignment(HorizontalAlignment::Center);
pButton2->setVerticalAlignment(VerticalAlignment::Bottom);
 
pContainer->add( pButton1 );
pContainer->add( pButton2 );
pContainer->add( pButton3 );

Grid layout 10.3

A GridLayout uses cells to arrange controls. There’s no row, column, or cell controls to keep track of. The root controls inside the GridLayout are arranged in invisible cells based on the order they appear in your code. Each of these cells behaves like a DockLayout, and supports both horizontal and vertical alignment. The columnCount property is used to specify how many vertical columns are present in the grid layout. The default number of columns for a grid layout is two.

The size of the cells depends on the size of the controls in the cells, and the size you set on the parent container holding the grid layout. You can use the preferredHeight, preferredWidth, minHeight, minWidth, maxHeight and maxWidth properties to specify the size of the parent container. If you don’t specify a size for the cells, Cascades uses the size of the child controls to arrange the cells automatically. If you set a specific size on the parent container using the preferredHeight and preferredWidth properties, the cells are distributed evenly as long as the child controls don’t require more space.

You can use the HorizontalAlignment and VerticalAlignment properties to further arrange controls in their cells.

Column count

The key difference between a grid layout and the other layout types is the columnCount property. Using columnCount, you can arrange multiple controls quickly and with minimal code. The following image shows five button controls arranged in a basic grid layout. A columnCount of 3 is given to create the arrangement:


A screen shot showing five buttons in a grid layout.

Using a grid layout in QML

The following code sample shows you how to specify the position of five buttons, as shown in the screen shot above, in QML:

Container {
    layout: GridLayout {
      columnCount: 3
    }
    Button {
        text: "Control 1"
    }
    Button {
        text: "Control 2"
    }
    Button {
        text: "Control 3"
    }
    Button {
        text: "Control 4"
    }
    Button {
        text: "Control 5"
    }
}

Using a grid layout in C++

The following code sample shows you how to specify the positioning of five buttons, as shown in the screen shot above, in C++:

#include <bb/cascades/Container>
#include <bb/cascades/GridLayout>
#include <bb/cascades/Button>

Container* pContainer = new Container();
GridLayout *pGridLayout = new GridLayout();
pGridLayout->setColumnCount(3);
pContainer->setLayout(pGridLayout);

Button* pButton1 = Button::create().text("Control 1");
Button* pButton2 = Button::create().text("Control 2");
Button* pButton3 = Button::create().text("Control 3");
Button* pButton4 = Button::create().text("Control 4");
Button* pButton5 = Button::create().text("Control 5");

pContainer->add( pButton1 );
pContainer->add( pButton2 );
pContainer->add( pButton3 );
pContainer->add( pButton4 );
pContainer->add( pButton5 );

Positioning

In the example above, only the columnCount property is used to arrange controls in a grid layout. The real power of a grid layout comes when you use additional positioning properties (such as HorizontalAlignment) to further tweak the positions of child controls. The following code sample creates a grid layout that uses multiple properties to arrange child controls:

import bb.cascades 1.3

Page {
    Container {
        Container {
            preferredHeight: 250
            horizontalAlignment: HorizontalAlignment.Fill
            layout: GridLayout {
                columnCount: 3
            }
            Container {
                background: Color.DarkRed
                preferredHeight: 250
                preferredWidth: 100
                horizontalAlignment: HorizontalAlignment.Left
            }
            Container {
                background: Color.DarkYellow
                preferredHeight: 50
                preferredWidth: 100
                horizontalAlignment: HorizontalAlignment.Right
                verticalAlignment: VerticalAlignment.Center
            }
            Container {
                preferredHeight: 50
                background: Color.DarkBlue
                preferredWidth: 100
                horizontalAlignment: HorizontalAlignment.Left
                verticalAlignment: VerticalAlignment.Bottom
            }
            Container {
                background: Color.DarkCyan
                preferredHeight: 250
                horizontalAlignment: HorizontalAlignment.Fill
            }
            Container {
                preferredHeight: 250
                background: Color.DarkGreen
                horizontalAlignment: HorizontalAlignment.Fill
            }
            Container {
                preferredHeight: 250
                background: Color.DarkMagenta
                horizontalAlignment: HorizontalAlignment.Fill
            }
        }
    }
}

The above code sample creates a grid layout that looks like this:


A grid layout with six containers arranged using multiple positioning properties.

In the example above, the width of the upper cells is determined by the fixed sizes of the bottom cells, which leaves space for the controls (in this case, containers) in the upper cells to align left and right.

Using margins

By default, UI controls are positioned with a small amount of space between each other in a layout. If you want to add more space between controls, you can set margins by specifying values for a control's margin properties:  leftMargin rightMargin topMargin, and  bottomMargin.

Margins refer only to the space between adjacent controls in a layout. You can also add space between a control and the edge of its parent container. This space is called padding, and is discussed in the next section.

If two controls with margins are positioned next to each other in a layout, their margins collapse and the space between them becomes the larger of the two margins. For example, consider two controls that are positioned next to each other in a left-to-right stack layout. If the right margin of the first control is 20 pixels and the left margin of the second control is 10 pixels, the actual space between the controls is 20 pixels. The 10 pixel margin collapses into the larger 20 pixel margin.

The image below illustrates how margins collapse between controls. The gray areas represent the margins around each text control, and you can see how the margins between adjacent controls overlap (collapse). In your own apps, you might use different margins for different text sizes, but use the same margins for all other controls.


Diagram showing margin overlap.

Here's how to create a top-to-bottom stack layout with three buttons, each of which has either a top or bottom margin, in QML. The margin between the second and third buttons is collapsed and takes on the value of the larger margin.

Container {
    layout: StackLayout {}
 
    Button {
        bottomMargin: 10
    }
 
    Button {
        bottomMargin: 10
    }
 
    Button {
        topMargin: 50
    }
}

In C++, the process is similar:

// Create the container and layout
Container* myContainer = new Container;
StackLayout* layout = new StackLayout;
myContainer->setLayout(layout);
 
// Create buttons with margins
myContainer->add(Button::create()
              .bottomMargin(10));
myContainer->add(Button::create()
              .bottomMargin(10));
myContainer->add(Button::create()
              .topMargin(50));

The code samples above both generate the button arrangement that you see to the right.

A screen shot showing three Button controls in a stack layout.

Using padding

When you add UI controls to a container, the controls are positioned at the edges of the container unless you specify a center alignment for the control. You can use padding to add empty space between the edges of the container and the controls inside it. By using padding, you can create the same amount of space between a container's edge and all of its child controls, instead of specifying margins for each child control separately.

You specify padding directly inside the control that you want the padding applied to (for example, inside a container if you want to create space between the edge of the container and the controls inside it). You can use the  topPadding bottomPadding leftPadding, and  rightPadding properties to create padding for the corresponding edge of the container.

The following images demonstrate what padding looks like. The image on the left doesn't include any padding, while the image on the right uses the topPadding and leftPadding properties:


Diagram showing the use of the topPadding and leftPadding properties.

Here's how to create the layout that you see in the image on the right, in both QML and C++:

Code sample: Applying padding in QML

Container {
    layout: StackLayout {}
    topPadding: 30
    leftPadding: 30
 
    Button {}
 
    Button {}
}

Code sample: Applying padding in C++

Container* myContainer = Container::create()
                         .top(30)
                         .left(30);
StackLayout* myLayout = new StackLayout;
myContainer->setLayout(myLayout);
 
myContainer->add(Button::create());
myContainer->add(Button::create());

Last modified: 2014-05-14



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus