Screens

You can use a Page to represent a screen in your app. In QML, you can specify the content that the Page should display by using the content property. This property accepts a UI control as the root control that's displayed on the screen. Here's how to create a Page with a Button as its root control:

import bb.cascades 1.0
 
Page {
    Button {
        text: "Root button"
    }
}
Page* myPage = new Page;
myPage->setContent(Button::create("Root button"));

The content property is the default property of a Page, meaning that you don't need to use "content:" explicitly when you want to add a control in QML. You can simply add the control directly to the Page:

import bb.cascades 1.0
 
Page {
    Button {
        text: "Root button"
    }
}

Not applicable

Page accepts only one control as its content. In the example above, the content of the Page is only the single Button; you can't add another Button, or any other control, to the content of the Page. If you call setContent() and specify a different control, the new control replaces the previous control as the content of the Page. Because of this, it can be a good idea to use a  Container as the content of your Page, and then add all other controls to the Container.

Here's how to create a Page that uses a Container as its content, in both QML and C++. The Container includes several other UI controls that are displayed on the screen.

import bb.cascades 1.0
 
Page {
    content: Container {
        Label {
            text: "A label"
        }
 
        Button {
            text: "A button"
        }
         
        Slider {
        }
    }
}
Page* myPage = new Page;
Container* rootContainer = new Container;
 
rootContainer->add(Label::create("A label"));
rootContainer->add(Button::create("A button"));
rootContainer->add(Slider::create());
 
myPage->setContent(rootContainer);

Title bar

The TitleBar comes in four different options specified by the TitleBarKind enum. The most basic is the default title bar, which supports title text and actions for accepting or dismissing an option.

The default title bar.

The segmented title bar supports a segmented control and is useful for filtering or modifying content that is displayed on the page.

A segemented title bar.

The third option is the text field title bar which contains a text field that can accept text from the user.

A title bar with a text field.

And the fourth option is the free-form title bar which represents an expandable title bar that can contain any controls that you want.

An expandable title bar.

Here's how to create the segmented title bar from the examples above. The title bar has two options: one for sorting alphabetically and another to sort by group.

Page {
    titleBar: TitleBar {
        kind: TitleBarKind.Segmented
        options: [
            Option {
                text: "A-Z"
            },
            Option {
                text: "Group"
            }
        ]
    }
}
#include <bb/cascades/Option>
#include <bb/cascades/Page>
#include <bb/cascades/TitleBar>
#include <bb/cascades/TitleBarKind>
Option* option1 = Option::create()
                 .text("A-Z");
Option* option2 = Option::create()
        .text("Group");
TitleBar *segmentedBar = TitleBar::create(TitleBarKind::Segmented)
        .addOption(option1)
        .addOption(option2);
Page *root = Page::create().titleBar(segmentedBar);

Sticky and non-sticky title bars

A title bar can be useful to let users know where they are in the navigation hierarchy of your app, as well as to provide confirm and cancel options. However, on smaller screens, the title bar can consume screen space that could be put to better use.

By default, when an app is run on an all-touch device and a screen in the app includes a title bar, the title bar is sticky. That is, if the content area is scrollable (for example, if it includes a ListView or ScrollView as its root control), when users scroll, the title bar remains at the top of the screen.

However, on a device with a physical keyboard, the title bar is non-sticky by default. If the content area is scrollable, when users scroll, the title bar scrolls along with the content and disappears from the top of the screen. This behavior allows you to display more scrollable content on the smaller screen.

You can use the scrollBehavior property of a TitleBar to determine whether a title bar is sticky or non-sticky. This property accepts values from the TitleBarScrollBehavior::Type enumeration, such as TitleBarScrollBehavior::Sticky and TitleBarScrollBehavior::NonSticky.

If a title bar includes any action items on it, the title bar can only be sticky and it cannot be specified as non-sticky. For example, if you use the acceptButton property of a TitleBar to specify an action item that represents a confirm action, the title bar will always remain at the top of the screen (sticky behavior) regardless of the scrollBehavior value that you specify.

Actions

You can add actions to a  Page by using the actions property. Actions are displayed as buttons at the bottom of the screen and represent actions that users might want to perform on that screen. For example, a screen for composing a new email might include actions to send the email, file it to complete later, or delete it.

You use an  ActionItem to represent an action. An ActionItem can include both descriptive text and an image, and it emits the  triggered() signal when it's selected. You can respond to this signal by using the predefined onTriggered signal handler in QML, or by connecting the signal to a slot in C++. When you use an image on an ActionItem, the image is centered on the action button. If you don't specify an image, one is added automatically for you.

Screen showing a set of actions at the bottom of a screen.

By default, actions that you add to a Page appear in an action menu, which is positioned on the right side of the action bar and looks like a series of three dots arranged vertically. Users can tap this menu to display the actions for the screen.


Screens illustrating how to display the action menu.

You can specify that you want an action to appear on the action bar by using the ActionBar.placement property. This property accepts enumeration values from the ActionBarPlacement class: InOverflow or OnBar. Actions that use ActionBarPlacement::OnBar are added to the action bar until there's no more room for additional actions. When the action bar is full, any extra actions are added to the action menu. Actions that use ActionBarPlacement::InOverflow are placed in the action menu but aren't displayed on the action bar.

It's important to note that the action menu is displayed only if you add actions that don't use the ActionBarPlacement::OnBar value (or if the action bar is full, as described above). In addition, if an action menu is displayed, the menu contains all of the actions for the Page, including those actions that already appear on the action bar. Consider the following examples that illustrate this behavior:

If you add an action that uses ActionBarPlacement::OnBar and another action that uses ActionBarPlacement::InOverflow, an action menu that contains both actions is displayed and only the first action appears on the action bar.

Screen showing a single action on the action bar, along with an action menu.

If you add two actions that both use ActionBarPlacement::OnBar, an action menu isn't displayed and both actions appear on the action bar.

Screen showing two actions on the action bar, without an action menu.
If you add two actions and neither one uses ActionBarPlacement::OnBar, an action menu is displayed that includes both actions and neither action appears on the action bar.
Screen showing no actions on the action bar, with an action menu.

Here's how to create a Page in QML with two actions, both of which are placed on the action bar using the ActionBar.placement property. When selected, each action changes the text of a Label:

import bb.cascades 1.0
 
Page {
    content: Container {
        Label {
            id: myLabel
            text: "Initial text"
        }
    }
     
    actions: [
        ActionItem {
            title: "Action 1"
            ActionBar.placement: ActionBarPlacement.OnBar
             
            onTriggered: {
                myLabel.text = "Action 1 selected!"
            }
        },        
        ActionItem {
            title: "Action 2"
            ActionBar.placement: ActionBarPlacement.OnBar
             
            onTriggered: {
                myLabel.text = "Action 2 selected!"
            }
        }  
    ]
}

Here's how to do the same thing in C++. The handleAction1() and handleAction2() functions are slots that handle the actions on the Page, and are connected to the triggered() signals of the actions.

// The variable myLabel is of type Label, and is declared in a
// header file so that the slots can access it. The slot functions
// handleAction1() and handleAction2() are also declared in the
// header file.
 
Page* root = new Page;
 
// Create the container and label
Container* topContainer = new Container;
mLabel = Label::create("Initial text");
topContainer->add(myLabel);
 
// Create actions for the screen, and connect the triggered()
// signal of each action to slot functions. Make sure to
// test the return value to detect any errors.
ActionItem* action1 = ActionItem::create()
        .title("Action 1");
ActionItem* action2 = ActionItem::create()
        .title("Action 2");
bool res = QObject::connect(action1, SIGNAL(triggered()), this,
                            SLOT(handleAction1()));
                            
// If any Q_ASSERT statement(s) indicate that the slot failed to
// connect to the signal, make sure you know exactly why this has
// happened. This is not normal, and will cause your app to stop
// working.
Q_ASSERT(res);
res = QObject::connect(action2, SIGNAL(triggered()), this,
                       SLOT(handleAction2()));
Q_ASSERT(res);
 
// Indicate that the variable res isn't used in the rest of the
// app, to prevent a compiler warning.
Q_UNUSED(res);
                  
// Add the actions to the page.
root->addAction(action1, ActionBarPlacement::OnBar);
root->addAction(action2, ActionBarPlacement::OnBar);
 
// Set the content of the page and display it.
root->setContent(root);
Application::setScene(root);

// The slot function for action 1
void App::handleAction1()
{
    mLabel->setText("Action 1 selected!");
}
 
// The slot function for action 2
void App::handleAction2()
{
    mLabel->setText("Action 2 selected!");
}

Action item images

Action item images are specified using the imageSource property for each action item you create. If necessary, action item images are scaled automatically by the platform.

To control the colorization of action item images, you need to create an .amd (asset metadata) file for each image you use, in the same folder as your image asset. In the .amd file, you can use the type attribute to enable or disable colorization. Setting a type of template enables colorization of an image. When colorization is enabled, Cascades colorizes the images automatically according to the device theme. A type of normal overrides the framework and uses the original image. The following code sample shows the structure of an .amd file for an image named myImage.png with a type of template:

#RimCascadesAssetMetaData version=1.1
type: template
source: "myImage.png"

To use colorization, the #RIMCascadesAssetMetaData version must be set to 1.1.

And here is the code required to add action item images:

ActionItem {
    title: "Action 1"
    ActionBar.placement: ActionBarPlacement.OnBar
    imageSource: "asset:///images/myImage.amd"
}, 

The following image shows how a white/grayscale icon can be colorized for each theme.


Screen shot showing the appearance of action item images with colorization.

And this example shows how you can have both colorized and overridden icons on the same action bar.


Screen shot showing the appearance of action item images with normal and template types.

For best practices on using color, check out the Color section of the UI Guidelines.

Signature action items 10.3

Signature action items allow you to draw attention to an action item with an additional visual cue. Making an action a signature action adds a colored circle around the action that extends into the main part of the screen.


Screen shot showing signature action items in both the light and dark themes.

To create a signature action item, you use ActionBarPlacement.Signature enum. The following code sample shows you how to create the three action items from the screen shots above:

import bb.cascades 1.3

Page {
    Container {
        Label {
            id: myLabel
            text: "Initial text"
        }
    }
    
    actions: [
        ActionItem {
            title: "Action 1"
            ActionBar.placement: ActionBarPlacement.OnBar
            imageSource: "asset:///images/myImage.png"
            onTriggered: {
                myLabel.text = "Action 1 selected!"
            }
        },        
        ActionItem {
            title: "Signature"
            ActionBar.placement: ActionBarPlacement.Signature
            imageSource: "asset:///images/myImage.png"
            onTriggered: {
                myLabel.text = "Action 2 selected!"
            }
        },
        ActionItem {
            title: "Action 3"
            ActionBar.placement: ActionBarPlacement.OnBar
            imageSource: "asset:///images/myImage.png"
            onTriggered: {
                myLabel.text = "Action 2 selected!"
            }
        }  
    ]
}

There can only be one signature action displayed at a given time. If you try to specify more than one signature item, the last action in an action set with a placement of ActionBarPlacement.Signature becomes the signature item.

The color of a signature item background is blue by default. You can also set a custom color using the backgroundColor property:

ActionItem {
    title: "Signature"
    ActionBar.placement: ActionBarPlacement.Signature
    backgroundColor: Color.Green
    imageSource: "asset:///images/myImage.png"
        onTriggered: {
            myLabel.text = "Action 2 selected!"
        }
},

Auto-hiding action bar

When you include a scrolling list (or any other scrollable content) in your apps, there are some things that you need to consider when adapting the content to fit a smaller screen. You can fit more list items or scrollable content on all-touch devices because they have larger screens than devices with a physical keyboard. Depending on the structure of your app, displaying fewer list items or less scrollable content might negatively impact your app's user experience.

This problem is particularly evident when your app includes an action bar on the same screen as a list or scrollable content area. The action bar is displayed at the bottom of the screen, on top of any list items or scrollable content on the same screen. This placement can consume valuable screen space that could instead be used to display additional list items or scrollable content.

To help with this problem, the action bar disappears automatically in certain circumstances when an app is run on a device with a smaller screen. If your app includes a ListView or ScrollView as the main control on a screen (that is, as the root control of a Page), as users scroll downward, the action bar is hidden automatically so that additional list items or scrollable content items are visible. The action bar reappears when users reach the end of the list or scrollable content area, or if users start scrolling upward.


Screens showing that the action bar is displayed when a list is motionless and it is hidden when users scroll downward.

You can use the actionBarAutoHideBehavior property of a Page to determine whether the action bar is hidden automatically during scrolling. This property accepts values from the ActionBarAutoHideBehavior::Type enumeration, such as ActionBarAutoHideBehavior::HideOnScroll and ActionBarAutoHideBehavior::Disabled.

Here's how to create a Page that includes the actionBarAutoHideBehavior property in QML. A value of Disabled is used, which means that the action bar won't be hidden automatically during scrolling.

Page {
    actionBarAutoHideBehavior:ActionBarAutoHideBehavior.Disabled

    ListView {
        // Create your list content
        ...
    }
}
Page *rootPage = new Page();
rootPage->setActionBarAutoHideBehavior(ActionBarAutoHideBehavior::Disabled);

Adding actions dynamically

You can add actions to the action bar dynamically using the Delegate class. Dynamically adding actions allows you to respond to user behavior by offering additional actions and options in your app.

The following code sample shows you how to create an action item dynamically and add it to the action bar. Checking one or more of the CheckBox controls creates an action item and displays it on the action bar. Tapping the action clears the selected CheckBox controls, and disables the action. If you manually clear the CheckBox controls, the action item is disabled.

import bb.cascades 1.3

Page {
    id: mainPage
    property int actionIndex: 0
    
    Container {
        CheckBox {
            id: cb1
            text: "Option 1"
            onCheckedChanged: {
                if (checked == true) {
                    actionIndex ++;
                    dynamicActionItem.active = true;
                } else {
                    actionIndex --;
                    if (actionIndex == 0) {
                        mainPage.removeAction(dynamicActionItem.object);
                        dynamicActionItem.active = false;
                    }
                }
            }
        }
        CheckBox {
            id: cb2
            text: "Option 2"
            onCheckedChanged: {
                if (checked == true) {
                    actionIndex ++;
                    dynamicActionItem.active = true;
                } else {
                    actionIndex --;
                    if (actionIndex == 0) {
                        mainPage.removeAction(dynamicActionItem.object);
                        dynamicActionItem.active = false;
                    }
                }
            }
        }
        Label {
            text: actionIndex
        }
    }
    
    actions: [ dynamicActionItem.object ]
    
    attachedObjects: [
        Delegate {
            id: dynamicActionItem
            ActionItem {
                id: dynamicAction
                ActionBar.placement: ActionBarPlacement.OnBar
                onTriggered: {
                    cb1.checked = false;
                    cb2.checked = false;
                }
            }
        }
    ]
}

In the code sample above, the ActionItem is removed from the scene when it isn't needed. You could also set the enabled property to false to disable the action. A disabled action is visible on the action bar, but its appearance is dimmed and it can't be tapped.

Sheets

Page is designed to represent an entire screen in your app, and you can add Page objects to other navigation elements, such as a  NavigationPane or  TabbedPane. To learn how, see Drill down and Tabs.

Cascades includes another control to represent an entire screen in your app: a  Sheet. A Sheet is displayed as a layer on top of the current screen and represents a separate flow, or detour, from the main navigation of your app. For example, you might use a Sheet to allow users to compose an email or create a new contact.

Sheet can contain other navigation controls, such as  NavigationPane TabbedPane, or  Page, and it can include actions that appear in the action bar or action menu. When you open a Sheet, it appears from the right of the screen and covers the entire screen (including any other Sheet objects that might be open).


Screens showing how a sheet is displayed.

Any Sheet objects that you want to display are included in the attachedObjects list. Here's how to create and show a Sheet in QML:

import bb.cascades 1.0
 
Page {
    attachedObjects: [
        Sheet {
            id: mySheet
            content: Page {
                Label {
                    text: "This is a sheet."
                }
                 
                actions: [
                    ActionItem {
                        title: "Close Sheet"
                        ActionBar.placement: ActionBarPlacement.OnBar
                         
                        // When this action is selected, close
                        // the sheet
                        onTriggered: {
                            mySheet.close();
                        }
                    }
                ]
            }
        }    
    ]
     
    actions: [
        ActionItem {
            title: "Open Sheet"
            ActionBar.placement: ActionBarPlacement.OnBar
             
            // When this action is selected, open
            // the sheet
            onTriggered: {
               mySheet.open();
            }
        }
    ]
}

Here's how to do the same thing in C++:

// Create the UI controls
Page *root = new Page;
Sheet *mySheet = new Sheet;
Page *sheetPage = new Page;
Label* sheetLabel = Label::create("This is a sheet.");
 
// Create the actions to open and close the sheet, and add the actions
// to their appropriate pages
ActionItem *openSheet = ActionItem::create()
                         .title("Open Sheet")
                         .onTriggered(mySheet, SLOT(open()));
ActionItem *closeSheet = ActionItem::create()
                         .title("Close Sheet")
                         .onTriggered(mySheet, SLOT(close()));
sheetPage->addAction(closeSheet, ActionBarPlacement::OnBar);
root->addAction(openSheet, ActionBarPlacement::OnBar);
 
// Set the content of each page
sheetPage->setContent(sheetLabel);
mySheet->setContent(sheetPage);

Last modified: 2014-11-17



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

comments powered by Disqus