×
Namespaces

Variants
Actions

Implementing a Splash Screen with Qt Quick

From Nokia Developer Wiki
Jump to: navigation, search

This article explains how to implement a splash screen in Qt Quick using pure QML, or a combination of Qt C++ and QML. In addition, it provides tips and tricks on how to avoid the common pitfalls.

Article Metadata
Tested withCompatibility
Platform(s):
Symbian
Dependencies: Qt 4.8
Article
Created: Tomi_ (15 Mar 2012)
Last edited: hamishwillee (29 Oct 2013)

Contents

Introduction

The main purpose of the splash screen is to improve the user experience during application launch – displaying a screen immediately makes the app appear responsive, while attractive animations can distract the user from the wait time for full application boot (which takes at least three seconds for a Symbian application using Qt Quick Components). The splash screen is also an opportunity to promote application (or company) branding, and to provide other basic information like versioning.

When implementing a splash screen with Qt Quick, there are two choices: use either a Qt C++ and QML combination (referred to as "Combination approach" in this document) or to stick with QML only. The pure QML solution has the limitation that animations cannot be played while the main file is loaded - so some apps may need to restrict themselves to splash screens without animations to reduce the overall load time. The "Combination approach" requires the use of C++ but is even more straightforward, and does not block the UI while the main file is loaded.

The most important aspects you need to address when implementing a splash screen are the following:

  1. How to show the splash screen as fast as possible during app launch?
  2. How to design an efficient splash screen?
  3. How to handle the loading of the main application?
  4. How to switch the content with style (e.g. transitions) and how to clean up afterwards ( i.e. free the resources that are no longer needed)?

Note.pngNote: This article was mainly written for Symbian and therefore some of the content may not apply for Nokia N9 (MeeGo 1.2 Harmattan). While the general rules are the same, the code represented in the snippets might require some changes in order function properly on Harmattan.

Combination approach

Launching the splash screen

The simplest solution is to set the splash screen QML file as the source for QDeclarativeView in your main.cpp as soon as possible:

QDeclarativeView view;
...
view.setSource("MySplashScreen.qml");
view.showFullScreen();

This can be also done by a Qt C++ helper class:

// mView is a pointer to QDeclarativeView instance
QDeclarativeComponent splashScreenComponent(mView->engine(), QUrl::fromLocalFile("MySplashScreen.qml"));
QDeclarativeItem splashScreenItem = qobject_cast<QDeclarativeItem*>(splashScreenComponent.create());
splashScreenItem->setWidth(mView->width());
splashScreenItem->setHeight(mView->height());
mView->scene()->addItem(splashScreenItem); // The view takes ownership

Loading the main application

The main application is typically loaded using a Qt C++ helper class:

// mView is a pointer to QDeclarativeView instance
QDeclarativeComponent component(mView->engine(), QUrl::fromLocalFile("main.qml"));
QDeclarativeItem *mainItem = qobject_cast<QDeclarativeItem*>(component.create());
mView->scene()->addItem(mainItem); // The view takes ownership

This approach doesn't block the UI so using animations in your splash screen is not a problem.

Hiding and deleting the splash screen and showing the main content

There are several ways to hide the splash screen when implementing a combination approach. The simplest solution is to just delete the splash screen item but from a UX point of view, a simple transition like fading is preferred. You can implement the transition in your splash screen QML file:

Item {
id: splashScreen
 
signal hidden()
 
function startHideAnimation() {
hideAnimation.start();
}
 
...
 
SequentialAnimation {
id: hideAnimation
 
PropertyAnimation {
target: splashScreen
property: "opacity"
duration: 800
to: 0
}
ScriptAction { script: splashScreen.hidden(); }
}
}

Then connect the signal in your Qt C++ helper class:

// mSplashScreenItem is a member variable and a pointer to QDeclarativeItem
connect(mSplashScreenItem, SIGNAL(hidden()), this, SLOT(destroySplashScreen()));

After the main QML item is created, invoke the hiding animation of the splash screen:

QMetaObject::invokeMethod(mSplashScreenItem, "startHideAnimation");

And finally, once the animation is executed, hidden() signal is emitted which triggers your destroySplashScreen() method:

void MyMainAppLoader::destroySplashScreen()
{
mView->scene()->removeItem(mSplashScreenItem);
delete mSplashScreenItem;
}


Pure QML approach

The best way to architect an app with a splash screen in pure QML is to have a separate element to handle the loading of the splash screen and the main application, and to manage the content switching between them. This app loader is the QML file that you set as the source in C++, referred to below as MainAppLoader:

view.setSource("MainAppLoader.qml");
view.showFullScreen();

Care must be taken with the implementation of MainAppLoader to ensure that the splash screen is loaded and displayed quickly.

Launching the splash screen

The splash screen could be a static child element of the MainAppLoader but this would make it difficult to de-allocate its resources. Instead use the QML Loader element to dynamically allocate the splash screen. For example, in the MainAppLoader we load the splash screen as shown:

Loader {
id: splashScreenLoader // ID needed for so we can later delete the item
width: parent.width
height: parent.height
source: Qt.resolvedUrl("MySplashScreen.qml");
}

Setting the source property loads the splash screen as soon as the Loader has been constructed.

Note.pngNote: The main content is also created with a Loader. To ensure that the splash screen is drawn over the top of the main content (has a higher z order) you either need to either declare the loader for the the splash screen after the main content or explicitly set the z-order of the splash screen to be a high number

Loading the main application

There's not enough CPU time for the UI to do anything while the Loader element loads the main QML content. This means that any splash screen animations would stop while the main QML file is loaded. As a result, you need to delay loading the main file until the splash screen can be rendered on the screen and you should not have any animations running when the main file is loaded.

Warning.pngWarning: Do not load the main application content until the splash screen has been rendered (or do anything else that will put the CPU under pressure).

In your MainAppLoader you will have a Loader element for loading the main QML file:

Loader {
id: mainLoader
width: parent.width
height: parent.height
}

And a timer to delay the start of the loading procedure:

Timer {
id: firstPhaseTimer
interval: 700
running: true
repeat: false
 
onTriggered: {
if (!mainLoader.Loading) {
// Start to load the main application
mainLoader.source = Qt.resolvedUrl("main.qml");
secondPhaseTimer.start();
}
}
}

The second timer (secondPhaseTimer in the snippet above) is needed for hiding and deleting the splash screen, and will be covered in the last step.

Hiding and deleting the splash screen and showing the main content

Hiding the splash screen is implemented with a simple "Behavior on <property>" method:

Item {
id: splashScreen
...
Behavior on opacity { NumberAnimation { duration: 500 } }
}

The Timer elements can be used as described earlier. The second phase timer is needed because Timer elements are affected by the loading too; they stop while loading takes all the CPU time and when the loading is completed they try to catch up. Using two different timers solves this issue. The first timer was used to start the loading and the second is used to hide and delete the splash screen:

Timer {
id: secondPhaseTimer
property int phase: 0
interval: 1000
running: false
repeat: true
 
onTriggered: {
if (phase == 0) {
// Hide the splash screen
if (splashScreenLoader.item) {
splashScreenLoader.item.opacity = 0;
}
 
phase += 1;
}
else {
// Delete the splash screen.
//
// By setting the source property to an empty string destroys
// the loaded item.
splashScreenLoader.source = "";
secondPhaseTimer.stop();
}
}
}

You can, of course, use the same trigger for deleting the splash screen as described in Qt C++ approach earlier: make the splash screen emit a signal when it is hidden so you do not have to have "phases" in your timer.

Splash screen content

The splash screen must be displayed quickly in order to be effective. The splash screen QML element should only contain elements and graphics that can be loaded and displayed quickly. Do not use Qt Quick Components in a splash screen, as loading the Components takes a long time. Use only the general QML elements. You can still use graphics like small images, gradients in the background and even animations. There is no rule on the number of elements or images to use; the best way to evaluate the performance is by testing on the device. If your splash screen takes two seconds or more to load, you should consider optimising it. Note that the more elements and graphics you use, the more important it is to free the allocated resources afterwards.

Here are a few examples of different splash screens:

Back button

If the splash screen stays on the screen for a long time, for example while data is being retrieved over the network, it is recommended to provide not only information to the user about what is going on but also a possibility to cancel the launch. UX-wise the most straightforward approach is to provide a back button. Like discussed before, the button should not be implemented with Qt Quick Components, unless it is shown only after the Components have been loaded. Placing a custom button, with similar icon to Component's back button icon, to the bottom-left corner of the screen is easy:

Item {
width: ...
height: ...
 
anchors {
left: parent.left
bottom: parent.bottom
margins: 10
}
 
Image {
id: backIcon
anchors.fill: parent
source: "my-back-icon.png"
}
 
MouseArea {
anchors.fill: parent
onClicked: Qt.quit();
}
}

Make sure that the the quit() signal of the QDeclarativeEngine instance associated with the view is connected to the QApplication before showing the back button because otherwise tapping the button does nothing:

connect(mView->engine(), SIGNAL(quit()), qApp, SLOT(quit()));

If your main application is doing something that should not be interrupted, you should implement communication between the splash screen and the main application. This can be done, for example, with signals. When the user decides to cancel the loading by exiting, notify your main application and take appropriate measures and then do the exit. Fortunately, there is seldom need for implementing this.

Summary

This article covers the two main approaches for creating a splash screen with Qt Quick. The pure QML approach may not be suitable if you have an app with a long load time, and you want to use animations in your splash screen. The C++ approach is more flexible, but does require a bit more knowledge of C++.

Within these approaches there are possibilities for many different solutions. Just keep in mind the few basic rules: display the splash screen as quickly as possible, provide the user with relevant information or just a nice experience, and finally gracefully transition to the actual application content without adding delays unless necessary, e.g. in case you have some important information in your splash screen or your application needs to access data over network.

Finally, take advantage of the full source code of these examples with splash screens:

  • FileList: QML and Symbian only
  • ToDo Lists: Qt C++ & QML
  • Video Streamer: Qt C++ & QML, splash screen used to also handle the delay caused by loading data from the network
  • Weather Forecast: Qt C++ & QML, splash screen implemented for Symbian build only
This page was last modified on 29 October 2013, at 03:53.
232 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×