Add spacing and handling

Our UI is coming together nicely, but the sizes of the buttons in the lower section container don't quite match the sizes that appear in the final app. We can use space quotas to adjust the size of controls based on the space that's available to them. We can also add padding around the outside edge of the screen and add handling for button clicks to change the displayed layout accordingly.

Add space quotas and padding

If you look at the screen shot of our finished app, you see that the buttons get larger from left to right. To get this arrangement, we set the following space quotas for each of the buttons in our layout:

// Layout properties for the "Stack" button
layoutProperties: StackLayoutProperties {
    spaceQuota: 3
}
// Layout properties for the "Dock" button
layoutProperties: StackLayoutProperties {
    spaceQuota: 5
}
// Layout properties for the "Absolute" button
layoutProperties: StackLayoutProperties {
    spaceQuota: 7
}

Our UI controls are also quite close to the edges of the screen. For a more comfortable look, let's add some padding to our top-level container. Padding determines how much space appears between the edges of a container and the container's child controls. We use the topPadding, bottomPadding, leftPadding, and  rightPadding properties and add them to our top-level container (the container we created at the very beginning of the tutorial).

topPadding: ui.sdu(2)
bottomPadding: ui.sdu(2)
leftPadding: ui.sdu(2)
rightPadding: ui.sdu(2)

Add a signal handler

To finish our app, we need to connect the buttons so that the displayed layout changes when the corresponding button is clicked. You learn more about event handling in other tutorials, but here you get a taste of how to respond to simple events in QML.

Cascades uses a signals and slots model that is inherited from the underlying Qt framework. All UI controls in Cascades emit signals when particular properties change (such as size and visibility). You can learn a lot more about signals, slots, and event handling in other tutorials, but for now, it's enough to know that when a Button is clicked, it emits a signal called clicked(). We can respond to that event by using the onClicked signal handler.

First, we use this code for the stack layout button:

// onClicked for the "Stack" button
onClicked: {
    stackLayoutContainer.visible = true
    dockLayoutContainer.visible = false
    absoluteLayoutContainer.visible = false
    layoutNameLabel.text = "Stack layout"
}

Now we alter this code slightly for the other two buttons:

// onClicked for the "Dock" button
onClicked: {
    dockLayoutContainer.visible = true
    stackLayoutContainer.visible = false
    absoluteLayoutContainer.visible = false
    layoutNameLabel.text = "Dock layout"
}
// onClicked for the "Absolute" button
onClicked: {
    absoluteLayoutContainer.visible = true
    stackLayoutContainer.visible = false
    dockLayoutContainer.visible = false
    layoutNameLabel.text = "Absolute layout"
}
import bb.cascades 1.4

Page {
    content: Container {
        layout: DockLayout {}
        
        background: Color.create(0.2, 0.2, 0.2)
        
        topPadding: ui.sdu(2)
        bottomPadding: ui.sdu(2)
        leftPadding: ui.sdu(2)
        rightPadding: ui.sdu(2)
        
        Container {
            horizontalAlignment: HorizontalAlignment.Fill
            verticalAlignment: VerticalAlignment.Top
            
            Label {
                id: layoutNameLabel
                text: "Stack layout"
                horizontalAlignment: HorizontalAlignment.Center
                
                // Apply a text style to create large, light gray text
                textStyle {
                    base: SystemDefaults.TextStyles.BigText
                    color: Color.Gray
                }
            }
        } // end of upper section Container
        
        Container {
            layout: StackLayout {
                orientation: LayoutOrientation.LeftToRight
            }
            
            horizontalAlignment: HorizontalAlignment.Fill
            verticalAlignment: VerticalAlignment.Bottom

            Button {
                id: stackLayoutButton
                text: "Stack"
                
                // Layout properties for the "Stack" button
                layoutProperties: StackLayoutProperties {
                    spaceQuota: 3
                }
                
                // onClicked for the "Stack" button
                onClicked: {
                    stackLayoutContainer.visible = true
                    dockLayoutContainer.visible = false
                    absoluteLayoutContainer.visible = false
                    layoutNameLabel.text = "Stack layout"
                }
            }
            
            Button {
                id: dockLayoutButton
                text: "Dock"
                
                // Layout properties for the "Dock" button
                layoutProperties: StackLayoutProperties {
                    spaceQuota: 5
                }
                
                // onClicked for the "Dock" button
                onClicked: {
                    dockLayoutContainer.visible = true
                    stackLayoutContainer.visible = false
                    absoluteLayoutContainer.visible = false
                    layoutNameLabel.text = "Dock layout"
                }
            }
            
            Button {
                id: absoluteLayoutButton
                text: "Absolute"
                
                // Layout properties for the "Absolute" button
                layoutProperties: StackLayoutProperties {
                    spaceQuota: 7
                }
                
                // onClicked for the "Absolute" button
                onClicked: {
                    absoluteLayoutContainer.visible = true
                    stackLayoutContainer.visible = false
                    dockLayoutContainer.visible = false
                    layoutNameLabel.text = "Absolute layout"
                }
            }
        } // end of lower section Container
        
        // The middle section container
        Container {
            layout: StackLayout {}
            
            horizontalAlignment: HorizontalAlignment.Center
            verticalAlignment: VerticalAlignment.Center
            
            preferredWidth: ui.sdu(72)
            preferredHeight: ui.sdu(100)
            
            // A container to show the stack layout
            Container {
                id: stackLayoutContainer
                layout: StackLayout {
                    orientation: LayoutOrientation.LeftToRight
                }
                
                preferredWidth: ui.sdu(72)
                preferredHeight: ui.sdu(100)
                
                background: Color.create(0.3, 0.3, 0.3)
                
                // Images for the stack layout container
                ImageView { imageSource: "asset:///images/cow.png" }
                ImageView { imageSource: "asset:///images/cow.png" }
                ImageView { imageSource: "asset:///images/cow.png" }
            }
            
            // A container to show the dock layout
            Container {
                id: dockLayoutContainer
                layout: DockLayout {}
                
                preferredWidth: ui.sdu(72)
                preferredHeight: ui.sdu(100)
 
                background: Color.create(0.3, 0.3, 0.3)
                visible: false
                
                // Images for the dock layout container, each with dock layout properties
                ImageView {
                    horizontalAlignment: HorizontalAlignment.Left
                    verticalAlignment: VerticalAlignment.Center
                    
                    imageSource: "asset:///images/cow.png"
                }
                ImageView {
                    horizontalAlignment: HorizontalAlignment.Center
                    verticalAlignment: VerticalAlignment.Top
                    
                    imageSource: "asset:///images/cow.png"
                }
                ImageView {
                    horizontalAlignment: HorizontalAlignment.Right
                    verticalAlignment: VerticalAlignment.Bottom
                    
                    imageSource: "asset:///images/cow.png"
                }
            }
            
            // A container to show the absolute layout
            Container {
                id: absoluteLayoutContainer
                layout: AbsoluteLayout {}
                
                preferredWidth: ui.sdu(72)
                preferredHeight: ui.sdu(100)
                
                background: Color.create(0.3, 0.3, 0.3)
                visible: false
                
                // Images for the absolute layout container, each with absolute layout
                // properties
                ImageView {
                    layoutProperties: AbsoluteLayoutProperties {
                        positionX: 80
                        positionY: 300
                    }
                    imageSource: "asset:///images/cow.png"
                }
                ImageView {
                    layoutProperties: AbsoluteLayoutProperties {
                        positionX: 160
                        positionY: 200
                    }
                    imageSource: "asset:///images/cow.png"
                }
                ImageView {
                    layoutProperties: AbsoluteLayoutProperties {
                        positionX: 500
                        positionY: 750
                    }
                    imageSource: "asset:///images/cow.png"
                }
            }
        } // end of middle section Container       
    } // end of top-level Container
} // end of Page

That's it! Build and run the app one more time to see the finished product. Click the buttons to see the other layouts.

Screen showing the Layout sample app.

Handle different screen resolutions

If you run the app on a device such as the BlackBerry Passport smartphone, you might notice that we aren't really taking advantage of the 1440 x 1440 screen resolution. And if you run it on a device with a physical keyboard, you might notice that the UI doesn't even fit. Let's resolve these problems by using asset selection based on layout.

These asset selectors are available in API level 10.3 and later.

To enhance our UI for the BlackBerry Passport, we start by creating a folder with the name mindw120h120du in our assets folder. This folder lets us specify assets that apply only to screen layouts that are a minimum of 120 design units wide and 120 design units high. For more information about this syntax, see Layouts for display size. After you create this folder, go ahead and copy the main.qml file into it.

To make sure that our UI fits correctly on the BlackBerry Q10 or any other device with a resolution of 720 x 720, let's create a folder with the name mindw80h80du. You can copy the main.qml file from the assets folder into this folder, too.

Now, to be sure that our UI works well for the BlackBerry Z10 smartphone and BlackBerry Z30 smartphone, we create a folder with the name mindw76h128du and copy the main.qml file into it. Because our UI was built to suit a device with a screen resolution of 720 x 1280 in Create three layout containers, we don't have to change anything in this main.qml file. Our assets folder looks something like this now:

A screen showing the assets directory with layout folders for screen size and shape.

In the main.qml file in the mindw120h120du folder, we need to make some changes to the preferredWidth and preferredHeight properties. In the container for the middle section, change these properties as follows:

        Container {
            layout: StackLayout {}
            
            horizontalAlignment: HorizontalAlignment.Center
            verticalAlignment: VerticalAlignment.Center
            
            preferredWidth: ui.sdu(100)
            preferredHeight: ui.sdu(90)

            // ...

And in each of the containers to show the stack layout, dock layout, and absolute layout, set the same preferredWidth and preferredHeight values:

preferredWidth: ui.sdu(100)
preferredHeight: ui.sdu(90)

Go ahead and try the app on a BlackBerry Passport or use the BlackBerry 10 Device Simulator. Our UI fits nicely on a BlackBerry Passport now.

Screen showing the Layout sample app on a BlackBerry Passport.

In the main.qml file in the mindw80h80du folder, we need to make similar changes to the preferredWidth and preferredHeight properties that we set. In the container for the middle section, change these properties as follows:

preferredWidth: ui.sdu(60)
preferredHeight: ui.sdu(50)

We also need to change the position of the images in our absolute layout as follows:

                // Images for the absolute layout container, 
                // each with absolute layout properties
                ImageView {
                    layoutProperties: AbsoluteLayoutProperties {
                        positionX: 50
                        positionY: 100
                    }
                    imageSource: "asset:///images/cow.png"
                }
                ImageView {
                    layoutProperties: AbsoluteLayoutProperties {
                        positionX: 100
                        positionY: 150
                    }
                    imageSource: "asset:///images/cow.png"
                }
                ImageView {
                    layoutProperties: AbsoluteLayoutProperties {
                        positionX: 200
                        positionY: 200
                    }
                    imageSource: "asset:///images/cow.png"
                }

That's it, we're done. Our UI fits nicely on a BlackBerry Q10 now. And if a new device is introduced, we've got that scenario covered by the default main.qml file that we have in the top level of our assets folder.

Screen showing the Layout sample app on a BlackBerry Q10.

Last modified: 2015-03-31



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

comments powered by Disqus