Drawer Navigation App

June 20, 2016 — 26 Comments

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 SwipeView 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)

 

26 responses to Drawer Navigation App

  1. 

    “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.”
    It think this should be: “You can use a SwipeView with …”

  2. 

    Besides this, I would like to thank you for your great Blog and tutorials. I did learn a lot from you! Thank you!

  3. 

    Hi ekke, thank you for your great work on this blog. I found a bug on Android: When I open the Navigation-Drawer and tap on the Android BACK Key closes the APP. But this only happens if the Android BACK key has not been used elsewhere

    • 

      yep.
      in the new apps I published the back key should work better. have not added this to the older ones. Qt World Summit Conf App should contain newest.

      • 

        Thank you for your fast answer. In your “Qt World Summit Conf App” from Google Play Store the back-key-button works properly, but when I test the source code from your git, then the back-key doesn’t work.

      • 

        just tried. open some pages on stack, go back with Android BACK key. if root is reached, I’m opening the drawer to make it easy to jump to another part of the app.
        user must use android buttons to minimze and close. I’ll also add a ‘quit app’ as last entry in drawer.

      • 

        Normally, I use the system-back-key to close the drawer. In the Qt World Summit Conf App from Google Play this works properly (the drawer closing), but when I compile the source code and try to test it on my device, then the app is closed instead of the drawer.

      • 

        curious. yesterday compiled, built, deployed to Android 6 device and works as expected. Are you using Qt 5.8 ?

      • 

        Yes, I’m using Qt 5.8

      • 

        QtWS2016 – Open – Schedule – Tap on Session – Tap on Room
        BACK: Session Details
        BACK: schedule
        BACK: Opens Drawer
        BACK: Closes Drawer
        —-

      • 

        My System: Qt 5.8, Qt Creator 4.2.1, android-ndk-r10e

      • 

        same for me.
        and your device and android OS ?

      • 

        Android 7.0 on Samsung Galaxy S7; Android 6.0 on HTC Desire 816

      • 

        tested on BlackBerry Android DTEK50, Android 6.0.1
        later will test on Samsung (6.0.1) and Google (7.0) devices

      • 

        Thank you for your help

      • 

        thx for your help. it’s always my goal to provide apps with no issues.
        esp as next weeks work starts on QtWS2017 APP with some more features 😉

    • 

      @App-Monkey: This is not a bug in ekke’s source code. Drawer inherits from Popup, see QTBUG-59670

  4. 

    QtWS2016 – Open – Schedule -Tap on Session -Tap on Room
    BACK-Key: Session Details
    BACK-Key: Schedule
    BACK-Key: Opens Drawer
    BACK: Closes Drawer

    QtWS2016 – Open – Open Drawer
    BACK-Key: Closes App

    QtWS2016 from Play store – Open – Open Drawer
    BACK-Key: Closes Drawer
    BACK-Key: Popup (No more Pages)

    • 

      Can you please tell me how you intercepted the android-back-key to close the drawer in the QtWS2016 (PlayStore version)?
      Example:
      QtWS2016 – Open – Open Drawer
      BACK-Key: close Drawer <—- this one

  5. 

    Hallo Ekke, erstmal vielen herzlichen Dank für deine arbeit an diesem Blog, durch den ich sehr viel über qt/qml gelernt habe. Viele Grüße aus Rosenheim, Manuel

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 )

Facebook photo

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

Connecting to %s