Greatest challenge for complex mobile applications is to provide a smooth workflow, simple UI and great UX.
Smooth Workflows, clean structured APP
At first I’m always working on the workflows itself to enable users to do their work.I’m preparing this the ‘old way’ using paper and pencil.
Next step: your App needs an easy to understand structure. In most casesI’m using a TabbedPane as root where each Tab itself is a NavigationPane with some Pages on top.
Here’s the TabbedPane from TimeTracker:
If you’re using the ‘Personal Edition‘ the Tab ‘Upload’ wouldn’t be there, if you don’t use ‘NFC’ this Tab also would be hidden.
Report Tab shows a red splash – so requests some attention.
Clean Up your UI
Then going through customer requirements and putting all the fields on Pages.
Uuuups: … always happens that some Pages suddenly have too much stuff in there.
First solution: use ScrollViews.
Hint: It’s a good idea always to use ScrollViews to be sure all is reachable even on a small 720×720 scrreen.
Even with ScrollViews in many cases it doesn’t feel good with so many fields on a Page.
So the next step is a difficult one:
- HowTo reduce the amount of content per Page?
- Only show most important informations on first Page
- Make all the other data available on demand and
- Push additional content on top
- or Separate Page content using Segmented TitleBar
Here’s a Segmented TitleBar:
Now the content is much more cleaner separated and there’s some space for Images, large Icons or Backgrounds or simply space on Z30:
and here on smaller screen of Q5 / Q10:
To let the User immediately know about important data I placed some easy to understand Icons on the first Segment.
Tapping on an icon directly jumps to the Segment or opens corresponding Calendar Event or Notebook Entry:
Dynamic Pages will tell you more.
Important: Use always same Icons for same Actions and always follow same ‘rules’:
per ex. TimeTracker uses
- colored Icons if data is available
- gray Color if data could be entered optional
- nearly invisible (Opacity 0.3) Icons if data doesn’t exist
Also important: always use same position on screen: top-left for Geolocations
Icons can tell the whole story: left screenshot clearly states that there are 2 Geopositions from Start and Stop, right screenshot means there are no Geolocations.
Sheets or Pages
On top of NavigationPane you can push Pages to create a stack of Pages. From top Page you can go Back to underlying Page.
Sometimes you have to solve a Subtask: Cascades uses Sheets for this – from a Sheet you explicitely have to Cancel or Save.
Go through the workflows and make decisions where Pages will be used and where you need Sheets to separate a Task.
If all works well for normal situations discuss with users where they miss a short way and perhaps add an Action to directly jump into another Tab or open a Page from another place.
Finished all of this ? Now it’s a good point to think about …
Re-Use Components
This is the stage where I’m trying to re-use as much stuff as possible and create custom objects with own properties as API:
- Sheets
- Pages
- Containers
- ListItems
Here’s a Page with some custom properties:
Page { id: trackedListPage property string name: "trackedListPage" property bool isHistory: false property string historyMonth: "" property bool isAccounting: false property string fromDay: "" property string toDay: "" titleBar: TitleBar { title: isHistory ? qsTr("Tracked Times (History)") : qsTr("List of Tracked Times") } // ... }
QML makes it very easy to re-use Components.
Signals and Slots
A good UI always reflects what happens under the hood, so rethinking and enhancing the Signals / Slots concept is a good idea.
Whenever it makes sense it’s better to send a Signal instead of calling a function directly. To enable this perhaps some functions must be moved ‘nearer to the Root Object’ to be availabe as Slot from Signals sent out by different Pages on top.
Always make all changes immediately visible without telling the user to tap on a ‘refresh’ Icon – your app should be so intelligent to know when and where UI must be refreshed.
Create dynamic and destroy
Best UI isn’t the best UI if it’s slow or the APP is memory-hungry. Wherever possible Objects should be created lazy or only on demand and destroyed after each use.
Cascades provides different ways to dynamically create Objects.
If you’re not sure if you really should create a Page every time it’s pushed: try it out. If it’s fast enough do it. Cascades under the hood has some caching logic and even creating complex Objects (from my experiences) is really fast.
There’s another chapter on ‘UX Highlights – Dynamic Pages‘ where I will explain HoTo design dynamic pages depending on data and settings. I don’t want to confuse you, but this has nothing to do with the decision to create Objects dynamically only if they’re needed as explained here.
One of the ways to create dynamically is to use Delegates:
Tab { id: homeTab title: qsTr("Tracking Live") description: qsTr("Start | Stop Tracking") imageSource: "asset:///images/tracking.png" HomePage { id: homePage } } // end homeTab Tab { id: reportingTab title: qsTr("Report") description: qsTr("Finish an Accounting Period") imageSource: "asset:///images/create_report.png" delegateActivationPolicy: TabDelegateActivationPolicy.ActivateWhenSelected delegate: Delegate { ReportingPane { } } } // end reportingTab
First tab (homeTab) was created statically directly while starting the app. This is the first Tab visible – so we need this immediately. HomePage.qml will be instatiated.
The other one (reportingTab) is not instatiated at Startup. Cascades only knows that there could be a Tab containing a NavigationPane (ReportingPane). In this case it’s a lazy loading. Using ‘ActivateWhenSelected‘ means this tab will be created the first time the user taps on it. At startup only Icon and Title will be used. App-Start will be fast. Using Policy ‘ActivatedWhileSelected‘ the content will always be created if Tab was selected and destroyed if another tab will become active. This not only speeds-up start-time but also frees some memory.
For most of my Tabs I’m using ‘ActivateWhenSelected‘ but all Pages pushed on top of a Tab are created every time. (using ComponentDefinition or ControlDelegate)
On C++ use Singletons and from Constructor do only what really must be done at the beginning. All other stuff can be done lazy if a Class was first time used. This will speed up start time. Not only the App likes it to run fast – also Users like to …
Speed things up (NFC and more)
One of the last steps is to see where workflows can be automated or where NFC Tags can make life easier.
Read more about NFC Tags and TimeTracker here.
At the end you’ll have an APP users like to work with.
Settings to Customize
At the very beginning TimeTracker was a simple app to start and stop times.
In the meantime it’s a real Business APP solving requirements from SMB (Small medium Business) and Enterprises and also Single-users like Freelancers.
Take some time before using TimeTracker and go through the Settings to get YOUR customized APP. Pages can be look very different depending from Properties set.
I’m also working on ways to reduce complexitiy to make it easy to understand.
It’s also a good idea to think about different ways to do the input.
Some more informations on UX Highlights can be found here:
- Navigation concepts
- Lists: colorized, dimmed and Marker Icons
- Charts
- Dynamic Pages
- Reduce Complexity
- Flexible Input
- Never More Black Screens
It’s only the tip of an Iceberg, but I hope you got a feeling what can be done with native Cascades Apps. If you have some nice ideas to improve things I would be glad to hear about.
You must be logged in to post a comment.