Drawer Navigation App

June 20, 2016 — Leave a comment

Overview

This is part 6 of a series of demo apps helping you to understand Qt 5.7 for x-platform development on Android and iOS. This app demonstrates using a Drawer to navigate and contains some concepts explained before. Please read the blogs abvout my other Examples before:

  1. First app with One Page
  2. StackView
  3. SwipeView
  4. TabBar
  5. Bottom Navigation

Bottom Navigation is good for Apps with 3 – 5 different areas. If your app covers more aspects, then a Drawer is the way to go. Read at Google Material Style Guide about Drawer Navigation and take a look at Qt documentation on Drawer – a Navigation Control from Qt Quick Controls 2.

I tried to implement different functionality into the Drawer:

  • Header with Logo and Text
  • Items with Icon + Text
  • Items with Text-only (typically About, Help, Info)
  • Dividers to separate different areas
  • Subtitles
  • Showing a Counter (per ex. Number of emails, Orders, …)
  • Showing a colored Marker
  • Highlighting current Selection

See this Screenshot:

drawer2

As you know, I’m developing crossplatform Business Apps for BlackBerry10, Android, iOS. One of the most important requirements is a fast and smooth workflow through an App which includes short ways for the fingers to tap on buttons. To open a Drawer there are two ways:

  • Swipe from the left site to see the destinations
  • Tap on Menu Button (top-left)

drawer-menu-button

Both actions are not easy for one-hand-use. That’s why I liked the introduction of Bottom Navigation by Google. HowTo use this with Qt 5.7 we talked about in my previous example app.

Why not combining both ? Drawer and Bottom Navigation ? From Settings you can switch Bottom Navigation for Favorites on:

settings

As you can see I set Home, Car, Flight, Settings as ‘Favorite Destinations’. In this example app this decision was made fix – in a real life app the user should select favorites. Please note, that the left most Button is the Menu Button to open the Drawer.

Now it’s easy to open most-used Buttons or the Drawer from Menu at Bottom Navigation.

Favorites as Bottom Navigation will only be there if APP is in Portrait Mode.

Coming from BlackBerry 10 Cascades ? This looks similar to TabbedPane, where Tabs are shown on ActionBar. Makes it easy to have consistant workflow x-platform.

From Settings you also can Hide the TitleBar and decide if active selection should be highlighted.

Navigation Model

Items in Drawer and Buttons in Bottom Navigation are drawn by Repeater from Navigation Model, which is an array of:

[ 
	{ "type": "../navigation/DrawerNavigationButton.qml", 
	"name": "Home", 
	"icon": "home.png", 
	"source": "../navigation/HomeNavigation.qml", 
	"showCounter":false, 
	"showMarker":false, 
	"a_p":1},
	{...}
]

‘type’ can be:

  • DrawerNavigationButton.qml
  • DrawerDivider.qml
  • DrawerSubtitle.qml

‘name’, ‘icon’, ‘source’ are used to generate NavigationButtons

‘showCounter’, ‘showMarker’ adds this behavior to a NavigationButton

‘a_p’ means activationPolicy

From this NavigationModel the Drawer can be created easy. If Bottom navigation is in-use, same Model is used from a mapping:

property var favoritesModel: [
        0, 3, 7, 9
    ]

Be Dynamic (ActivationPolicy)

Coming from BlackBerry10 Cascades ? TabbedPane is similar to Drawer and TabbedPane has a TabDelegateActivationPolicy for dynamic loading of Tabs. I implemented similar policies for Draqwer Navigation.

I’m using Loaders to create Destinations. There are three Activation Policies:

  • IMMEDIATELY
  • LAZY
  • WHILE_CURRENT

IMMEDIATELY: .active = true for the Loader, so the Item was always loaded at the beginning and stays loaded.

LAZY: .active = false for the Loader. First time the Item inside the Loader  will be used, activate is set to true and will stay true. LAZY is good for performance at the beginning and will be used for items user normaly will access meny times.

WHILE_CURRENT: .active = false for the Loader. .active will only set to true WHILE the Item is the currentItem. If user switches to another node, the Loader will set .active = false. Next time same node is used, Item will created again. This option is good for memory-hungry complex Pages, the User normaly only will use seldom. Attention: As soon as the Item was unloaded, you lost your state. If you want to remember last sate, you must store the values anywhere.

For this Example APP here are the Activation Policies used to demonstrate how it’s done:

  • IMMEDIATELY: Home Page, Flight Page
  • LAZY: Car, Bus, Truck, Color Schema Pages
  • WHILE_CURRENT: Subway Page, Settings, About

Starting the App, all Destinations will be created from Repeater:

Repeater {
    id: destinations
    model: navigationModel
    // Destination encapsulates Loader
    // depends from activationPolicy how to load dynamically
    Destination {
	id: destinationLoader
    }
    Component.onCompleted: {
	// all destinations (Loader) created
	// all destinatation items w activationPolicy IMMEDIATELY activated
	// now show first destination (should always be IMMEDIATELY)
	rootPane.activateDestination(0)
    }
}

All marked as IMMEDIATELY will become active and loaded. When all is done, the first one will replace the initial item on StackView. Drawer is using a StackView where the root Item always will be replaced by the Item selected from Drawer or Bottom Navigation. In a real life App perhaps it could take some time before all is created, so there’s an InitialItemPage showing a BusyIndicator.

busy_indicator

Chances are great that you never will see this Page from Example App, because it’s only a demo app with less logic or data-loading behind.

Here’s the Destination.qml (Loader):

Loader {
    id: pageLoader
    property int pageActivationPolicy: modelData.a_p
    active: pageActivationPolicy == activationPolicy.IMMEDIATELY
    visible: false
    source: modelData.source
    onLoaded: {
        item.init()
        if(pageActivationPolicy != activationPolicy.IMMEDIATELY) {
            rootPane.replaceDestination(pageLoader)
        }
    }
}

There are two functions – activateDestinations() and replaceDestination() – managing the load / unload and refresh() on StackView. You can study this from sources.

Pages, StackView, SwipeView / TabBar

It depends from your use-cases what happens if User selects a destination. You can use a Page if there’s only one Page needed to show the content. You can use a StackView with TabBar and/or PageIndicator to provide sub-navigation as done for the ColorSchema where you can swipe through 3 Pages to select Primary Color, Accent Color and Theme or you can use a StackView.

The concept is the same as already described in Bottom Navigation APP – Activation Policies are first time used here in this App.

If using some nodes with StackViews where the User wants to jump between and expects to get the same leaf, don’t use Activation Policy WHILE_SELECTED.

Take a look at the sources to see How I implemented all this stuff. As in previous Examples there’s a init() function and cleanup() function to simulate some biz logic.

Coming from BlackBerry10 Cascades ? Here’s (from a 4-years-old Blog😉 How a typical Cascades App can be structured:

cascades-app

Compare this with a Qt 5.7 App designed with Material Style for Android and iOS as done for this Example, you’ll recognize a similar architecture. This is great for x-platform app development and why I prefer to use Qt 5.7 for Android / iOS Apps: much stuff from C++ is same, Event handling using SIGNAL / SLOT is similar and also UI Architecture as we have seen now.

qt-app

 

Providing same Workflow for mobile Business Apps for all target Platforms is important – esp. in Enterprise.

Sources

as usual at Github: https://github.com/ekke/drawer_nav_x

Summary

You learned HowTo use Qt Quick Controls 2 to implement Drawer Navigation.

Stay tuned for the next Example Apps …


← Back (Bottom Navigation App)

→ Next Article (Business Data App)

⇐ Home (Overview / Topics)

 

No Comments

Be the first to start the conversation!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s