Qt Quick Components provides two methods for application navigation. The PageStack system provides a way of navigating a hierarchy of pages. It is a stack that you can push pages of content onto and pop pages off the stack. The page at the top of the stack is what the user sees. The other method is to create pages in tabs. With the tabs system, the pages are arranged in a tab and the user can select the pages by clicking on the tabs.
A Page component serves as a container for other QML content. A page may contain additional components such as a TextEdit or Button components.
A Page may be created by defining the page inline or by encapsulating it in a Component element. Inline definitions of pages are ideal for small pages, however, all of the pages will remain in memory during creation. To exert control over the creation and destruction of a page, encapsulate them in a Component element.
Alternatively, a page can be defined in its own .qml file. This makes it easier to locate the source for each page and maintain the pages. It also makes it easier to share page implementations between applications.
You can integrate the PageStack with the ToolBar. This allows the pages to use the same instance of the ToolBar and run synchronized animations with the push and pop operations. This integration happens at the root level of your application, usually in the Window.
PageStack { id: pageStack toolBar: commonToolBar anchors { left: parent.left; right: parent.right; top: parent.top; bottom: toolBar.top } } ToolBar { id: commonToolBar anchors.bottom: parent.bottom }
The snippet above creates a PageStack and a ToolBar. The toolBar property of the PageStack binds to the created toolbar. This property binding allows the PageStack to update the application level ToolBar instance automatically when it changes the active Page.
Because the ToolBar instance is already created, the only thing left for the Page is to define the content - this is done by populating the tools property of the Page.
In the snippet below, a ToolBarLayout is used to position the ToolButton components.
Page { id: firstPage tools: ToolBarLayout { id: pageSpecificTools ToolButton { iconSource: "toolbar-back"; onClicked: Qt.quit() } ToolButton { text: "next page"; onClicked: pageStack.push(secondPage) } } }
The tools content is re-parented to the ToolBar instance when the page is shown.
Pushing a page to the stack will make the page visible to the user. The stack can store many pages and to navigate back, the stack can pop pages. The stack can replace the top page with a different page (or pages) rather than popping and pushing pages. In all these cases, the page stack performs appropriate transition animations to help the user understand a change is occurring.
There are basically three ways you can push a page onto the stack:
Encapsulating page definitions in a Component element means you can defer their creation and memory does not need to be allocated until the page is needed. Further, the page stack instantiates the page and destroys the instance when the page is popped from the stack. This means you don't have to worry about memory management since it is all handled by the page stack. As well, pages as components allow multiple instances of a particular page type to be at the stack. This means you can define one component with configurable variations rather than defining a separate item for each variation.
The ToolBar instance can be used for page navigation.
Page { id: firstPage tools: ToolBarLayout { id: pageSpecificTools ToolButton { iconSource: "toolbar-back"; onClicked: Qt.quit() } ToolButton { text: "next page"; onClicked: pageStack.push(secondPage) } } } Page { id: secondPage tools: ToolBarLayout { ToolButton { iconSource: "toolbar-back"; onClicked: pageStack.pop() } } }
The ToolButton can be bound to the PageStack commands such as push and pop. This way the page navigation can be made more intuitive for the end user.
The PageStack's busy property evaluates to true when the stack is changing pages. The busy property is useful for notifying the application when the stack changes to prevent unintentional events or user input.
MouseArea { anchors.fill: parent enabled: pageStack.busy }
Binding this property can disable mouse interaction within a MouseArea.
Alternatively, the Tab component can contain Page items. The parallel arrangement of pages are managed by the tab and clicking on a tab switches the visible pages.
The buttons are implemented with the TabButton component. You can layout these buttons as you like. In the ToolBar, the ButtonRow is used for laying. This also changes the buttons graphical presentation to match the ToolBar's look and feel.
ToolBarLayout { ToolButton {...} // back button ButtonRow { TabButton {...} TabButton {...} }
You can use TabBarLayout, and TabBar in Symbian, to layout buttons for a stand-alone tool bar. In this case, the you must position the TabBarLayout.
TabBarLayout { anchors.top: parent.top width: parent.width TabButton {...} TabButton {...} }
The tab content is managed by the TabGroup component whose child items are content items.
TabGroup { anchors {...} // user needs to layout the tab group Page { id: tab1Content } Page { id: tab2Content } }
The button and the content items are linked together with the TabButton's tab property.
TabButton { id: tab1Button; tab: tab1Content }
Once the linking is established, the TabButton and TabGroup components manage the tab content switching and also highlight the corresponding tab button.
In most cases, the tab count is static. Therefore, you can statically allocate child items of TabGroup and the layouting component as described above. In some cases, you have to add or remove tabs dynamically depending on the application state.
You can append a tab by creating a new TabButton as a child of the layout and similarly creating a new content item as the TabGroup's child. In addition, you need to set the TabButton's tab property to point to the new content item.
If you need to re-arrange the tab buttons, you need to clear the layout and append the buttons again in the correct order. The item order in the TabGroup does not affect the shown tab order.
You can remove a tab by deleting TabButton and the content item instances with destroy().
Use Qt.createComponent() to load the pages only when you need a page, use Component.createObject() to parse the page and create an instance of it. Note that normal property bindings cannot be used because you are using a component, rather than a specific QML object. To get around this, you need to specify a map of properties and values when the component is instantiated. See Dynamic Object Management in QML for more details.