Jun 28

Application Development : Defining the Application Structure (part 2) – Single Page Applications – Page Actions

2. Single Page Applications

A single Page application is entirely built around a unique Page at the root of the scene graph. You have been essentially designing single Page applications until now. The biggest advantage of the single Page application structure is not only its simplicity, but also the capacity to provide the user a single screen where all content and Actions are presented in an extremely focused way during the entire application lifetime. You might think that building your application around a single Page might lack the flexibility required for more complex interactions. You will, however, see that you can provide a very enticing user experience based on the single Page design using the controls presented in the following sections (you will also be able to extend very naturally the concepts introduced for single Page applications to multiple Page or navigation-based apps).

Actions

I have informally mentioned Actions when I discussed the Action bar. This section will show you how to implement them in practice in your own applications. There are several places where you can define Actions:

  • You can add Actions to a Page by setting the Page’s Actions property. You can also specify whether the Actions are displayed on the Action bar or in the Action overflow menu (by default, page Actions are located in the overflow menu and only the most used Actions should appear on the Action bar).
  • You can add context Actions to a UIControl, which will be displayed in a context menu when the user touches and holds the control in your app.
  • Finally, you can add Actions to a TitleBar.

2.1 ActionItem

An ActionItem object represents the actual Action. You can specify the following properties when declaring an ActionItem:

  • ActionItem::title: A text string that will be displayed with the Action (for example, on the Action bar or in a menu).
  • ActionItem::imageSource: A URL specifying the image set on the Action.

When the user triggers the Action, the ActionItem::triggered() signal is emitted. You can therefore use the onTriggered: handler in QML in order to react to user Actions.

2.2 Page Actions

Listing 1 illustrates how Actions are added to a Page control.

Listing 1.  Actions

import bb.cascades 1.0
Page {
        actions: [
        ActionItem {
            id: action1
            title: "action1"
            onTriggered: {
                actionLabel.text = action1.title
            }
        },
        ActionItem {
            id: action2
            title: "action2"
            onTriggered: {
                actionLabel.text = action2.title
            }
 
       }
       ]
    Container {
        Label {
            id: actionLabel
            text: "Hello Actions"
            textStyle.base: SystemDefaults.TextStyles.BigText
            horizontalAlignment: HorizontalAlignment.Center
        }
    }
}

Figure 2 shows the action bar when all Actions are located in the overflow menu.

Figure 2. Actions overflow menu

And Figure 3 displays the expanded overflow menu.

Figure 3. Expanded overflow menu

If you want to display actions directly on the Action bar, you need to set the ActionItem’s ActionBar.placement property to ActionBarPlacement.OnBar (see Listing 2 and Figure 4).

Listing 2. Actions on Action Bar

import bb.cascades 1.0
 
Page {
        actions: [
        ActionItem {
            id: action1
            title: "action1"
            ActionBar.placement: ActionBarPlacement.OnBar
            onTriggered: {
                actionLabel.text = action1.title
            }
        },
        ActionItem {
            id: action2
            title: "action2"
            ActionBar.placement: ActionBarPlacement.OnBar
            onTriggered: {
                actionLabel.text = action2.title
            }
        }
        ]
    Container {
        Label {
            id: actionLabel
            text: "Hello Actions"
            textStyle.base: SystemDefaults.TextStyles.BigText
            horizontalAlignment: HorizontalAlignment.Center
            contextActions:[

        }
    }
}

Figure 4. Actions on Action bar

2.3 Context Actions

You can also associate actions to a UIControl by setting the UIControl::contextActions property (see Listing 3).

Listing 3.  Context Actions

import bb.cascades 1.0
 
Page {
    Container {
        Label {
            id: actionLabel
            text: "Hello Actions"
            textStyle.base: SystemDefaults.TextStyles.BigText
            horizontalAlignment: HorizontalAlignment.Center
            contextActions: [
                ActionSet {
                    Title:
                    ActionItem {
                        id: action1
                        title: "action1"
                        ActionBar.placement: ActionBarPlacement.OnBar
                        onTriggered: {
                            actionLabel.text = action1.title
                        }
                    }
                    ActionItem {
                        id: action2
                        title: "action2"
                        ActionBar.placement: ActionBarPlacement.OnBar
                        onTriggered: {
                            actionLabel.text = action2.title
                        }
 
                    }
                }
            ]
        }
    }
}

You need to touch and hold the Label in order to display the context Actions. Notice how the Actions are grouped in an Action set. (You can specify multiple Action sets, but at the moment, Cascades will take only the first one into account. This might change in future releases.)

Jun 28

Application Development : Defining the Application Structure (part 1) – Action Bar

In a very broad sense, application structure defines the way you organize your application to manage actions, menus, tabs, and, of course, navigation. You will see that BlackBerry 10 provides you lots of flexibility in the way the application flow and controls are visually organized and presented to the user. You are, however, encouraged to follow the BlackBerry 10 UI guidelines in order to guarantee the best user experience. You can also use the BlackBerry 10 wireframe design slides to plan your application screens and navigation. This section reviews the additional controls used to create a supporting structure for your application out of those controls. If you consider a spoken language analogy, controls would be words and application structure would be the sentences built with those words (and hopefully “grammatically correct sentences” dictated by the BlackBerry 10 UI guidelines).

You will find the UI Guidelines for BlackBerry 10 at http://developer.blackberry.com/devzone/design/bb10/.

The wireframe design slides can be downloaded from http://developer.blackberry.com/devzone/design/bb10/prototyping.html.

1. Action Bar

Before looking at different application structures, I want to explain the action bar: the Action bar is located at the bottom of the screen and can contain actions, tabs, and menus.  For example, in Figure 1, the Tabs are regrouped, and touching the Hub icon will reveal the remaining ones.

Figure 1. Action bar

The Action menu is located on the rightmost side of the Action bar. By pressing the icon with three vertical dots, the overflow menu is displayed with the corresponding Actions. Finally, Actions can appear directly on the action bar, which is the case of the Search and Compose Actions shown in Figure 1.

Jun 26

Application Development : Application Templates (part 3) – List View Template

List View Template

Listing 3 gives the main.qml generated by the List view template. (Listing 4 defines the page that is displayed when a ListView item is selected. Listing 5 defines the data to be loaded in the ListView.)

Listing 3.  List View Template, main.qml

import bb.cascades 1.0
NavigationPane {
    id: nav
    Page {
        Container {
            ListView {
                dataModel: XmlDataModel {
                    source: "data.xml"
                }
                onTriggered: {
 
                    if (indexPath.length > 1) {
                        var chosenItem = dataModel.data(indexPath);
                        var contentpage = itemPageDefinition.createObject();
 
                        contentpage.itemPageTitle = chosenItem.name
                        nav.push(contentpage);
                    }
                }
            }
 
        }
 
    }
    attachedObjects: [
        ComponentDefinition {
            id: itemPageDefinition
            source: "ItemPage.qml"
        }
    ]
    onPopTransitionEnded: {
        page.destroy();
    }
}

Listing 4.  List View Template, ItemPage.qml

import bb.cascades 1.0
 
Page {
    property alias itemPageTitle: titlebar.title
    titleBar: TitleBar {
        id: titlebar
    }
    Container {
 
    }
}

Listing 5.  data.xml

<root>
    <header title="Header 1">
        <item  name="Item 1"/>
        <item  name="Item 2"/>
        <item  name="Item 3"/>
        <item  name="Item 4"/>
        <item  name="Item 5"/>
    </header>
    <header title="Header 2">
        <item  name="Item 1"/>
        <item  name="Item 2"/>
        <item  name="Item 3"/>
        <item  name="Item 4"/>
        <item  name="Item 5"/>
        <item  name="Item Gorilla"/>
    </header>
</root>

Here are the most important aspects of the code to consider:

  • The root control is an instance of NavigationPane (again, this is a departure from the standard empty project that contained a Page control as the root container).  The NavigationPane provides the NavigationPane::push(bb::cascades::Page*) and the bb::cascades::Page* NavigationPane::pop() methods in order to implement navigation. If a page is pushed on the navigation stack, it will be displayed to the user. The opposite effect is achieved by popping the page off the stack. In this case, the page located at the top of the stack is displayed. You should note that a List view template is essentially a special case of a Navigation pane template where navigation is triggered by selecting data items in a ListView.
  • A ListView uses a DataModel in order to load its data. The ListView component has been designed around the MVC pattern. The DataModel implements the model part, the ListView plays the role of the controller, and a ListItemComponent handles the list view’s visuals.
  • The navigation pane’s attached object property includes a ComponentDefinition declaration, which is used to dynamically load a QML component (in this case, an instance of ItemPage, which is defined in ItemPage.qml, located in the same folder as main.qml). When you actually need to create the object, you will have to call ComponentDefinition.createObject().
  • Notice how the indexPath array length is checked before navigating to ItemPage to ensure that the user has selected an item element and not a header.
  • The root element index path will be the empty array. The header elements will have a one-element index path array and the item elements will have an index path array containing two elements.

Figure 3 illustrates the resulting application and Figure 4 UI when Item 2 is selected from the list.

Figure 3. Master view

Figure 4. Details view

By touching the Back icon, you will pop the current page from the NavigationPage’s stack and display the ListView, which will once again be at the top of the stack.

Jun 26

Application Development : Application Templates (part 2) – Navigation Pane Template

Navigation Pane Template

Listing 2 gives the main.qml file generated by the Navigation pane template.

Listing 2.  Navigation Pane Template, main.qml

import bb.cascades 1.0
 
NavigationPane {
    id: navigationPane
 
    Page {
        titleBar: TitleBar {
            // Localized text with the dynamic translation and locale updates support
            title: qsTr("Page 1") + Retranslate.onLocaleOrLanguageChanged
        }
 
        Container {
        }
 
        actions: ActionItem {
            title: qsTr("Second page") + Retranslate.onLocaleOrLanguageChanged
            ActionBar.placement: ActionBarPlacement.OnBar
 
            onTriggered: {
                // A second Page is created and pushed when this action is triggered.
                navigationPane.push(secondPageDefinition.createObject());
            }
        }
    }
 
    attachedObjects: [
        // Definition of the second Page, used to dynamically create the Page above.
        ComponentDefinition {
            id: secondPageDefinition
            source: "DetailsPage.qml"
        }
    ]
 
    onPopTransitionEnded: {
        // Destroy the popped Page once the back transition has ended.
        page.destroy();
    }
}

You can use the Navigation pane template to build drill-down applications. In Listing 2, a ComponentDefinition object is used to dynamically load a QML object defined in DetailsPage.qml (you will learn about ComponentDefinition in a moment). The root control is an instance of NavigationPane (this is a departure to a standard empty project, which contained a Page control as the root container).  The NavigationPane provides the NavigationPane::push(bb::cascades::Page*) and bb::cascades::Page* NavigationPane::pop() methods in order to implement navigation. If a page is pushed on the navigation stack, it will be displayed to the user. The opposite effect is achieved by popping the page off the stack. In this case, the new page located at the top of the stack is displayed. An ActionItem triggers the actual navigation from one page to another.

Jun 26

Application Development : Application Templates (part 1) – Tabbed Pane Template

The Momentics IDE’s New BlackBerry Project wizard is a great starting place for selecting your application scaffolding. You have the choice between four project templates, which basically cover most, if not all, of your needs in designing Cascades applications:

  • Standard empty project: This is the template you have been using until now for designing your applications. It provides you a single Page where you can add your own Cascades controls.
  • List view: Creates an application where the main UI element is a ListView displaying a list of items. The data for the list items is provided by an instance of a DataModel.
  • Tabbed pane: Creates an application where the user can switch between Tabs. Each Tab contains an instance of an AbstractPane (in practice, you can only add a Page or a NavigationPane to the Tab).
  • Navigation pane: Creates an application that uses a NavigationPane to display screens. Navigation is triggered when the user selects an action, which can be contextual or located on the Action bar (I will tell you more about actions and action bars in a moment).

Note that both the List view and the Navigation pane templates use navigation, which is a way to transition from one screen to another, in order to implement their functionality.

Let us now have a look at the main.qml files generated by each template (I am going to omit the standard empty project because you are already quite familiar with it).

Tabbed Pane Template

The main.qml file generated by the Tabbed Pane template is given in Listing 1.

Listing 1.  Tabbed Pane Template, main.qml

import bb.cascades 1.0
 
TabbedPane {
    showTabsOnActionBar: true
    Tab { //First tab
        // Localized text with the dynamic translation and locale updates support
        title: qsTr("Tab 1") + Retranslate.onLocaleOrLanguageChanged
        Page {
            Container {
                Label {
                    text: qsTr("First tab") + Retranslate.onLocaleOrLanguageChanged
                }
            }
        }
    } //End of first tab
    Tab { //Second tab
        title: qsTr("Tab 2") + Retranslate.onLocaleOrLanguageChanged
        Page {
            Container {
                Label {
                    text: qsTr("Second tab") + Retranslate.onLocaleOrLanguageChanged
                }
            }
        }
    } //End of second tab
}

A tabbed pane is an extremely convenient way of organizing your application in multiples screens. Each Tab can contain an instance of an AbstractPane (in other words, you can use a Page or a NavigationPane as a child control). Figure 1 illustrates a resulting UI where the second tab has been selected.

Figure 1. Tabs on Action bar with second Tab selected

You can specify how a TabbedPane will appear on the Action bar by setting its ShowTabsOnActionBar property. If you change the property to false (or if you don’t set it at all), the resulting layout will be identical to Figure 2.

Figure 2. Tabs in overflow menu

By touching the Tab1 icon, you will reveal the other tabs. Obviously, this layout is preferable if you have lots of tabs in your application.

Jun 24

Application Development : System Dialogs, Prompts, and Toasts (part 3) – SystemToast

SystemToast

A toast is a simple pop-up message that is displayed for a predefined amount of time. The toast is for information purposes only and the user does not need to interact with it. Listing 4 shows you how to use a SystemToast to display a toast to the user.

Listing 4.  SystemToast

import bb.cascades 1.2
import bb.system 1.2
 
Page {
    Container {
        layout: DockLayout {
        }
        Button {
            text: "Show Dialog!"
            verticalAlignment: VerticalAlignment.Center
            horizontalAlignment: HorizontalAlignment.Center
            onClicked: {
                myToast.show();
            }
        }
        attachedObjects: [
            SystemToast {
                id: myToast
                body: "Happy New Year!"
            }
        ]
 
    }
}

Jun 24

Application Development : System Dialogs, Prompts, and Toasts (part 1) – SystemPrompt

SystemPrompt

You can use a SystemPromptto ask for some input from the user before continuing with your application flow. The SystemPrompt will display two default buttons for accepting or rejecting the dialog box and an input field for user input. You can retrieve the user’s input by calling SystemPrompt.inputFieldTextEntry() (see Listing 2).

Listing 2.  SystemPrompt

import bb.cascades 1.2
import bb.system 1.2
 
Page {
    Container {
        layout: DockLayout {
             
        }
        Button {
            text: "Show Dialog!"
            verticalAlignment: VerticalAlignment.Center
            horizontalAlignment: HorizontalAlignment.Center
            onClicked: {
                myPrompt.show();
            }
        }
        attachedObjects: [
            SystemPrompt {
                title: "Enter a new file name"
                id: myPrompt
                onFinished: {
                    switch (value) {
                        case (SystemUiResult.ConfirmButtonSelection):
                            console.log("new file name is: "+myPrompt.inputFieldTextEntry())
                            break;
                        case (SystemUiResult.CancelButtonSelection):
                            console.log("new file canceled");
                            break;
                        default:
                            break;
                    }
                }
            }
        ]
 
    }
}

Figure 2 shows the SystemPrompt when displayed.

Figure 2. SystemPrompt

Jun 24

Application Development : System Dialogs, Prompts, and Toasts (part 1) – SystemDialog

You can use the system dialog controls to pause your application flow and communicate important information to the user. System dialogs can be used to ask the user to confirm an action, notify the user of an event, or prompt the user for additional information.

SystemDialog

You can use a SystemDialog control to ask the user to confirm an action (see Listing 1). (Note that you need to import the bb.system 1.2 library.)

Listing 1.  SystemDialog with User Confirmation

import bb.cascades 1.2
import bb.system 1.2
 
Page {
    Container {
        layout: DockLayout {
        }
        Button {
            text: "Show Dialog!"
            verticalAlignment: VerticalAlignment.Center
            horizontalAlignment: HorizontalAlignment.Center
            onClicked: {
                myDialog.show();
            }
        }
        attachedObjects: [
            SystemDialog {
                title: "Save Changes"
                id: myDialog
                onFinished: {
                    switch (value) {
                        case (SystemUiResult.ConfirmButtonSelection):
                            console.log("save confirmed");
                            break;
                        case (SystemUiResult.CancelButtonSelection):
                            console.log("save canceled");
                            break;
                        default:
                            break;
                    }
                }
            }
        ]
 
    }
}

To display the dialog, you need to call SystemDialog.show(). To determine the user’s selection, you need to handle the SystemDialog.finished() signal. The SystemDialog’s text property will be displayed on the dialog’s title bar (see Figure 1).

Figure 1. SystemDialog

Jun 24

Application Development : Controls – ScrollView

A ScrollView is a container allowing the scrolling and zooming of its content. A ScrollView provides a viewport, which displays an area of the entire content. You can use a ScrollView when the content will not fit the UI entirely (for example, that would be the case if a container included many controls). Note that a ScrollView’s content can also be an ImageView or a WebView (for example, you can use a ScrollView to zoom in or out of a picture). You can control the scrolling behavior by setting the ScrollView’s scrollViewProperties property. Listing 1 shows you how to include a WebView in a ScrollView.

Listing 1.  ScrollView

Page {
    ScrollView {
        WebView {
            url: "http://www.apress.com
"
        }
        scrollViewProperties {
            scrollMode: ScrollMode.Vertical
            pinchToZoomEnabled: true
        }
    }
}

Use a ScrollView when

  • A control’s content does not fit the screen and you need to provide a viewport that you can navigate (by scrolling horizontally and/or vertically).
  • You need to zoom in or out of content using a pinch gesture.

Jun 21

Application Development : CheckBox and ToggleButton

Check boxes and toggle buttons enable users to select options. Both controls inherit from AbstractToggleButton and share the following attributes:

  • You can use the checked property to determine the state of the toggle control.
  • You can handle the checkedChanged signal to capture state changes.

CheckBox

A CheckBox control has two states: checked or unchecked. You can also optionally display some text beside the check box explaining its purpose. If you include some text, it will always be left-aligned, and the check box will be right-aligned (see Figure 1).

Figure 1. CheckBox

Listing 1 shows you how to handle check box states in QML.

Listing 1.  CheckBox

CheckBox {
    id: checkbox
    checked: true
    text: "Checkbox"
    onCheckedChanged: {
        console.log("checkbox state: " + checkbox.checked)
    }
}

In practice, use check boxes when users can select multiple items or options, which are not mutually exclusive.

ToggleButton

A toggle button is a kind of switch control, which can, for example, represent On/Off states (see Figure 2). Signal handling is identical to a check box.

Figure 2. ToggleButton

You should use a toggle button when users can switch between two mutually exclusive options, such as On and Off.

Older posts «