Implementing custom orientation changes animation with QML
This code example shows how to override the default QML orientation change animation with your own custom orientation change. The orientation change is detected with QOrientationSensor.
Article Metadata
Code Example
Tested with
Compatibility
Article
Contents |
Overview
Qt Quick Components provide a standard animation between orientations on Symbian (in Maemo the orientation is already locked to the landscape mode). If the orientation is not locked, QML apps can monitor the change through the QML Window element, or by observing the width and height of the main window and seeing which one is the greatest. This approach should be perfectly acceptable for almost all Qt apps.
This code example shows how you can change the default animation if you need to. This is achieved by first locking the orientation to portrait mode to prevent the default animation occurring. We then use the QOrientationSensor to detect when the orientation has changed, provide this data to QML using Signals and Slots, and perform the animation in QML.
Pros and cons of this approach:
- + Nice animation to the orientation change
- + No black screen during the orientation change
- - Custom implementation is required to switch to landscape orientation when HW-keyboard is used
- - Additional (though user-grantable) capability ReadDeviceData is required to allow reading of sensors on Symbian
- - Qt Mobility libraries are required to detect the orientation
Download the sources of this snippet here.
Preconditions
- Qt 4.7 or higher is installed on your platform
- QtMobility 1.0.2 or higher is installed on your platform
orientation.pro
The declarative module is used, as well as the Qt Mobility sensors. QML code will be placed inside Qt resource system for easier deployment to the devices.
QT += core gui declarative
TARGET = orientation
TEMPLATE = app
SOURCES += main.cpp
HEADERS += orientationfilter.h
OTHER_FILES += Orientation.qml
RESOURCES = resources.qrc
CONFIG += mobility
MOBILITY += sensors
symbian {
# To lock the application to landscape orientation
LIBS += -lcone -leikcore -lavkon
}
unix:!symbian {
maemo5 {
target.path = /opt/usr/bin
} else {
target.path = /usr/local/bin
}
INSTALLS += target
}
main.cpp
The main.cpp creates the QOrientationSensor and the self-implemented OrientationFilter which will signal the changes of the orientation. This signal is connected to the QML documents root elements function orientationChanged. The root element is retrieved by using code view.rootObject().
The width and height of the root element are set to be resized to QDeclarativeViews sizes with the code view.setResizeMode(QDeclarativeView::SizeRootObjectToView).
#include <QApplication>
#include <QDeclarativeView>
#include <QGraphicsObject>
#include <QDesktopWidget>
#include <QOrientationSensor>
#include "orientationfilter.h"
QTM_USE_NAMESPACE
#ifdef Q_OS_SYMBIAN
// Lock orientation in Symbian
#include <eikenv.h>
#include <eikappui.h>
#include <aknenv.h>
#include <aknappui.h>
#endif
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
#ifdef Q_OS_SYMBIAN
// Lock orientation in Symbian
CAknAppUi* appUi = dynamic_cast<CAknAppUi*> (CEikonEnv::Static()->AppUi());
TRAP_IGNORE( if(appUi) { appUi->SetOrientationL(CAknAppUi::EAppUiOrientationPortrait); } );
#endif
QDeclarativeView view;
view.setSource(QUrl("qrc:/Orientation.qml"));
view.setResizeMode(QDeclarativeView::SizeRootObjectToView);
QOrientationSensor sensor;
OrientationFilter filter;
sensor.addFilter(&filter);
// Connect the Qt signal to QML function
QObject::connect(&filter, SIGNAL(orientationChanged(const QVariant&)), view.rootObject(), SLOT(orientationChanged(const QVariant&)));
sensor.start();
// Show application in full screen on all platforms with corresponding device resolution
view.setGeometry(QApplication::desktop()->screenGeometry());
view.showFullScreen();
return app.exec();
}
orientationfilter.h
The self-implemented OrientationFilter] is derived from QObject to get the possibility to emit signals and from QOrientationFilter to read the values of the sensor. The sensor reading is placed to QVariant so that the value can be passed to JavaScript function in QML code.
#ifndef ORIENTATIONFILTER_H
#define ORIENTATIONFILTER_H
#include <QOrientationFilter>
QTM_USE_NAMESPACE
class OrientationFilter : public QObject, public QOrientationFilter
{
Q_OBJECT
public:
bool filter(QOrientationReading *reading) {
emit orientationChanged(reading->orientation());
// don't store the reading in the sensor
return false;
}
signals:
void orientationChanged(const QVariant &orientation);
};
#endif // ORIENTATIONFILTER_H
Orientation.qml
The UI holds six Text elements inside a Column representing orientations of the device. Current orientation text will be shown as bold and white color as the others are shown in black without bold. The view will be rotated to the current orientation by altering the rotation property of the view. Also the width and height of the view are updated to match the corresponding orientation.
import Qt 4.7
Item {
id: base
function orientationChanged(orientation) {
highlightindex(orientation)
if(orientation == 1) {
view.rotation = 0
view.width = base.width; view.height = base.height
}
else if(orientation == 2) {
view.rotation = 180
view.width = base.width; view.height = base.height
}
else if(orientation == 3) {
view.rotation = 270
view.width = base.height; view.height = base.width
}
else if(orientation == 4) {
view.rotation = 90
view.width = base.height; view.height = base.width
}
}
function highlightindex(orientation) {
var count = texts.children.length
for(var i=0; i<count; i++) {
if(i == (orientation - 1)) {
texts.children[i].color = "white"
texts.children[i].font.bold = true
}
else {
texts.children[i].color = "black"
texts.children[i].font.bold = false
}
}
}
Rectangle {
id: view
Behavior on rotation { RotationAnimation { direction: RotationAnimation.Shortest; duration: 500; easing.type: Easing.OutBounce } }
Behavior on width { NumberAnimation { duration: 500 } }
Behavior on height { NumberAnimation { duration: 500 } }
anchors.centerIn: parent
width: base.width; height: base.height
color: "blue"
Column {
id: texts
anchors.centerIn: parent
spacing: 10
Text { text: "Top up" }
Text { text: "Top Down" }
Text { text: "Left Up" }
Text { text: "Right Up" }
Text { text: "Face Up" }
Text { text: "Face Down" }
}
}
}
Postconditions
The snippet demonstrated the implementing of nice animation to orientation change with QML language. The orientation data was provided by Qt Mobilitys QOrientationSensor class. The retrieved data was transferred via Qt Signals and Slots to QML code where the current orientation was nicely visualized.


Contents
Ieatlint - Don't use any QSensor to detect orientation changes for UI
This article is wholly wrong. It will lead to additional power consumption by activating a sensor that is unneeded, and lead to unexpected behaviour, especially on devices with slide-out keyboards.
Why this is wrong:
So what's the proper way to do this? In the example above, you would need to create a new class inheriting QDeclarativeView. Add an event handler for resizeEvent(). In the event handler, test if the widget width exceeds the widget height. If it does, you're in landscape, otherwise you're in portrait. Send signals to the QML as needed here. I would recommend adding a variable to track what your current orientation is, and only causing a layout update if it changes -- sometimes you'll get a resize event that doesn't require you alter your layout, and you're wasting resources and it may be visible to the user.
This method will always keep your application in sync with what the phone's UI orientation is. It require no additional libraries, Symbian capabilities, or sensor readings. I've used this in Symbian and Maemo 5 with both widget-based UIs and QML..ieatlint 22:54, 18 July 2011 (EEST)
Forum Nokia KB - Known Issues Board 110901
Article needs further review. Re-evaluate in next KIBo.Forum Nokia KB 09:59, 1 September 2011 (EEST)
Kratsan - Reply to Don't use any QSensor to detect orientation changes for UI
This article was written to implement orientation change with nice animations, the most important point of the article was to remove the black screen that the Symbian OS does between the orientation change.
To achieve this behavior these two steps are required:
The detection of the HW keyboard of E7 is lacking in this snippet and some code should be added to detect and inform the UI accordingly.
I think nowadays Qt code could be moved to QML code, because the QtMobility bindings are available. The QML OrientationSensor http://doc.qt.nokia.com/qtmobility-1.2/qml-sensors.html should give all the required information.kratsan 10:21, 1 September 2011 (EEST)
Korva - Solution in Qt Components
For everyone seeking guidance from here (this entry is pretty high on google search):
You can use the Window component from the new Qt Quick Components to very easily take care of orientation detection. If you use Window as the parent element, just query the inPortrait property. It handles the E7 keyboard open -scenario correctly. Documentation: http://doc.qt.nokia.com/qt-components-symbian-1.0/qml-window.html
Taking Qt Quick components into use: http://doc.qt.nokia.com/qt-components-symbian-1.0/index.htmlkorva 13:02, 29 September 2011 (EEST)
Hamishwillee - Added ArticleNeedsUpdate template
Hi Korva, Kratsan
Korva, thanks for the comment. I agree. I've added the ArticleNeedsUpdate template with this information so that people see it "up front".
Kratsan, would it be possible for you to re-write this article with the new mechanisms in mind? Or to create a new one? BTW, thanks for this article, very helpful prior to proper mechanisms being created.
Regards
Hamishhamishwillee 03:09, 5 October 2011 (EEST)
Tomi - The Times They Are a-Changin'
Hello all,
I feel that the animated orientation change using Qt Quick Components is too small of a subject to require a new article. As for this article, I'd suggest archive or remove.
Regards,
TomiTomi_ 17:00, 23 February 2012 (EET)
Hamishwillee - Kind of, but this article is accurate
Hi Tomi, Ieatlint
After discussion with the author I concluded that the article is accurate but was/is subject to mis-interpretation.
The right/normal way to do transition animations is to use the standard animations you get from Qt Quick Components and follow the various other instructions in the doc about orientation and scalability. You can also use the Window Element if you need to do any processing before or after a transition.
This article is for the small subset of cases where the normal transitions are NOT sufficient. This is IMO a valid use case to document, as long as its made clear this is not the "standard" way.
I have updated the overview appropriately. I have renamed to make it clear this is "Custom". Feel free to review or update the article overview more if you think I haven't been sufficiently clear.
regards Hamish
PS I plan to remove these comments in a couple of days.hamishwillee 04:13, 27 February 2012 (EET)