Commit cda75160 authored by Leena Miettinen's avatar Leena Miettinen
Browse files

Doc: update scalability information


Add information about scaling on high DPI screens.

Task-number: QTBUG-38859
Change-Id: If3a037305d5470107ba7b8f710b1ae69372ab235
Reviewed-by: default avatarTopi Reiniö <topi.reinio@digia.com>
Showing with 286 additions and 22 deletions
...@@ -28,22 +28,33 @@ ...@@ -28,22 +28,33 @@
/*! /*!
\title Scalability \title Scalability
\page scalability.html \page scalability.html
\brief How to develop applications that scale well on devices that offer \brief How to develop applications that scale well on devices with different
different screen sizes. screen configurations and UI conventions.
\ingroup best-practices \ingroup best-practices
When you develop applications for several different mobile device platforms,
you face the following challenges:
\list
\li Mobile device platforms support devices with varying screen
configurations: size, aspect ratio, orientation, and density.
\li Different platforms have different UI conventions and you need to
meet the users' expectations on each platform.
\endlist
Qt Quick enables you to develop applications that can run on different types Qt Quick enables you to develop applications that can run on different types
of devices, such as tablets and handsets. In particular, they can cope of devices, such as tablets and handsets. In particular, they can cope
with different screen configurations: size, density, orientation, with different screen configurations. However, there is always a certain
resolution, and aspect ratio. amount of fixing and polishing needed to create an optimal user experience
for each target platform.
You need to consider scalability when: You need to consider scalability when:
\list \list
\li You want to deploy your application to more than one device \li You want to deploy your application to more than one device
platform, such as Android, BlackBerry, and iOS, or more than one platform, such as Android, BlackBerry, and iOS, or more than one
device screen configuration or form factor. device screen configuration.
\li Your want to be prepared for new devices that might appear on the \li Your want to be prepared for new devices that might appear on the
market after your initial deployment. market after your initial deployment.
\endlist \endlist
...@@ -58,15 +69,16 @@ ...@@ -58,15 +69,16 @@
\li Use \e {property binding} to implement use cases \li Use \e {property binding} to implement use cases
not covered by the layouts. For example, to display alternative not covered by the layouts. For example, to display alternative
versions of images on screens with low and high pixel density or versions of images on screens with low and high pixel density or
automatically rotate view contents according to the current screen automatically adapt view contents according to the current screen
orientation. orientation.
\li Select a reference device and calculate a \e {scaling ratio} for
adjusting image and font sizes and margins to the actual screen
size.
\li Load platform-specific assets using \e {file selectors}. \li Load platform-specific assets using \e {file selectors}.
\li Load components on demand by using a \e {Loader}. \li Load components on demand by using a \e {Loader}.
\endlist \endlist
Consider an application that has to be deployed to devices that have Consider the following patterns when designing your application:
different screen configurations, form factors, or UI conventions. There are
some patterns that you might consider when designing your application:
\list \list
\li The contents of a view might be quite similar on all \li The contents of a view might be quite similar on all
...@@ -85,11 +97,15 @@ ...@@ -85,11 +97,15 @@
email viewer, if the screen is large enough, it may be possible to email viewer, if the screen is large enough, it may be possible to
show the email list view, and the email reader view side by show the email list view, and the email reader view side by
side. side.
\li The screen size and form factors of two devices might be quite similar, \li For games, you would typically want to create a game board that does not
but the UI conventions might be totally different. scale, so as not to provide an unfair advantage to players on larger
screens. One solution is to define a \e {safe zone} that fits the screen
with the smallest supported aspect ratio (usually, 3:2), and add
decorative-only content in the space that will be hidden on a 4:3 or
16:9 screen.
\endlist \endlist
\section1 Resizing Screens Dynamically \section1 Resizing Application Windows Dynamically
\l{Qt Quick Controls} provide a set of UI controls to create user interfaces \l{Qt Quick Controls} provide a set of UI controls to create user interfaces
in Qt Quick. Typically, you declare an ApplicationWindow control as the root in Qt Quick. Typically, you declare an ApplicationWindow control as the root
...@@ -102,13 +118,14 @@ ...@@ -102,13 +118,14 @@
In addition to controls that define standard parts of application windows, In addition to controls that define standard parts of application windows,
controls are provided for creating views and menus, as well as presenting or controls are provided for creating views and menus, as well as presenting or
receiving input from users. You can use \l{Qt Quick Controls Styles} to receiving input from users. You can use \l{Qt Quick Controls Styles} to
apply custom styling to the predefined controls. apply custom styling to the predefined controls. For examples of using the
styles, see \l{Qt Quick Controls - Touch Gallery}.
Qt Quick Controls, such as the ToolBar, do not provide a layout Qt Quick Controls, such as the ToolBar, do not provide a layout
of their own, but require you to position their contents. For this, you can of their own, but require you to position their contents. For this, you can
use Qt Quick Layouts. use Qt Quick Layouts.
\section1 Laying Out Screens Dynamically \section1 Laying Out Screen Controls Dynamically
\l{Qt Quick Layouts} provide ways of laying out screen controls in a row, \l{Qt Quick Layouts} provide ways of laying out screen controls in a row,
column, or grid, using the RowLayout, ColumnLayout, and GridLayout QML column, or grid, using the RowLayout, ColumnLayout, and GridLayout QML
...@@ -122,6 +139,53 @@ ...@@ -122,6 +139,53 @@
The layouts ensure that your UIs are scaled properly when windows and The layouts ensure that your UIs are scaled properly when windows and
screens are resized and always use the maximum amount of space available. screens are resized and always use the maximum amount of space available.
A specific use case for the GridLayout type is to use it as a row or a
column depending on the screen orientation.
\image scalability-gridlayout.png
The following code snippet uses
the \c flow property to set the flow of the grid from left to right (as a
row) when the screen width is greater than the screen height and from top to
bottom (as a column) otherwise:
\code
ApplicationWindow {
id: root
visible: true
width: 480
height: 620
GridLayout {
anchors.fill: parent
anchors.margins: 20
rowSpacing: 20
columnSpacing: 20
flow: width > height ? GridLayout.LeftToRight : GridLayout.TopToBottom
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: "#5d5b59"
Label {
anchors.centerIn: parent
text: "Top or left"
color: "white"
}
}
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: "#1e1b18"
Label {
anchors.centerIn: parent
text: "Bottom or right"
color: "white"
}
}
}
}
\endcode
Constantly resizing and recalculating screens comes with a performance cost. Constantly resizing and recalculating screens comes with a performance cost.
Mobile and embedded devices might not have the power required to recalculate Mobile and embedded devices might not have the power required to recalculate
the size and position of animated objects for every frame, for example. If the size and position of animated objects for every frame, for example. If
...@@ -146,7 +210,7 @@ ...@@ -146,7 +210,7 @@
space available. space available.
\endlist \endlist
\section1 Handling Pixel Density \section1 Using Bindings
If Qt Quick Layouts do not fit your needs, you can fall back to using If Qt Quick Layouts do not fit your needs, you can fall back to using
\l{Property Binding}{property binding}. Binding enables objects to \l{Property Binding}{property binding}. Binding enables objects to
...@@ -163,17 +227,18 @@ ...@@ -163,17 +227,18 @@
This type of positioning is the most highly dynamic. However, constantly This type of positioning is the most highly dynamic. However, constantly
evaluating JavaScript expressions comes with a performance cost. evaluating JavaScript expressions comes with a performance cost.
For example, bindings are a good way to handle low and high pixel density. You can use bindings to handle low and high pixel density on platforms that
The following code snippet uses the \l{Screen}{Screen.logicalPixelDensity} do not have automatic support for it (like OS X and iOS do).
The following code snippet uses the \l{Screen}{Screen.PixelDensity}
attached property to specify different images to display on screens with attached property to specify different images to display on screens with
low, high, or normal pixel density: low, high, or normal pixel density:
\code \code
Image { Image {
source: { source: {
if (Screen.logicalPixelDensity < 40) if (Screen.PixelDensity < 40)
"image_low_dpi.png" "image_low_dpi.png"
else if (Screen.logicalPixelDensity > 300) else if (Screen.PixelDensity > 300)
"image_high_dpi.png" "image_high_dpi.png"
else else
"image.png" "image.png"
...@@ -181,6 +246,181 @@ ...@@ -181,6 +246,181 @@
} }
\endcode \endcode
On OS X and iOS, you can provide alternative resources with double the size
and the \e @2x identifier for icons and images and place them in the
resource file. On Retina displays, the @2x versions are used automatically.
For example, the following code snippet will try to load \e artwork@2x.png
on Retina displays:
\code
Image {
source: "artwork.png"
}
\endcode
\section1 Handling Pixel Density
Some QML types, such as \l Image, BorderImage, and \l Text, are
automatically scaled according to the properties specified for them.
If the width and height of an Image are not specified, it automatically uses
the size of the source image, specified using the \c source property. By
default, specifying the width and height causes the image to be scaled to
that size. This behavior can be changed by setting the \c fillMode property,
allowing the image to be stretched and tiled instead. However, the original
image size might appear too small on high DPI displays.
A BorderImage is used to create borders out of images by scaling or tiling
parts of each image. It breaks a source image into 9 regions that are scaled
or tiled according to property values. However, the corners are not scaled
at all, which can make the results less than optimal on high DPI displays.
A \l Text QML type attempts to determine how much room is needed and set the
\c width and \c height properties accordingly, unless they are explicitly
set. The \c fontPointSize property sets the point size in a
device-independent manner. However, specifying fonts in points and other
sizes in pixels causes problems, because points are independent of the
display density. A frame around a string that looks correct on low DPI
displays is likely to become too small on high DPI displays, causing the
text to be clipped.
The level of high DPI support and the techniques used by the supported
platforms varies from platform to platform. The following sections describe
different approaches to scaling screen contents on high DPI displays.
For more information about high DPI support in Qt and the supported
platforms, see \l{High DPI Displays}.
\section2 High DPI Scaling on OS X and iOS
On OS X and iOS, applications use high DPI scaling that is an alternative to
the traditional DPI scaling. In the traditional approach, the application is
presented with an DPI value used to multiply font sizes, layouts, and so on.
In the new approach, the operating system provides Qt with a scaling ratio
that is used to scale graphics output: allocate larger buffers and set a
scaling transform.
The advantage of this approach is that that vector graphics and fonts scale
automatically and existing applications tend to work unmodified. For raster
content, high-resolution alternative resources are needed, however.
Scaling is implemented for the QtQuick and QtWidgets stacks, as well as
general support in QtGui and the Cocoa platform plugin.
The OS scales window, event, and desktop geometry. The Cocoa platform plugin
sets the scaling ratio as QWindow::devicePixelRatio() or
QScreen::devicePixelRatio(), as well as on the backing store.
For QtWidgets, QPainter picks up \c devicePixelRatio() from the backing
store and interprets it as a scaling ratio.
However, in OpenGL pixels are always device pixels. For example, geometry
passed to glViewport() needs to be scaled by devicePixelRatio().
The specified font sizes (in points or pixels) do not change and strings
retain their relative size compared to the rest of the UI. Fonts are
scaled as a part of painting, so that a size 12 font effectively becomes a
size 24 font with 2x scaling, regardless of whether it is specified in
points or in pixels. The \e px unit is interpreted as device independent
pixels to ensure that fonts do not appear smaller on a high DPI display.
\section2 Calculating Scaling Ratio
You can select one high DPI device as a reference device and calculate
a scaling ratio for adjusting image and font sizes and margins to the actual
screen size.
The following code snippet uses reference values for DPI, height, and
width from the Nexus 5 Android device, the actual screen size returned by
the QRect class, and the logical DPI value of the screen returned by the
\c qApp global pointer to calculate a scaling ratio for image sizes and
margins (\c m_ratio) and another for font sizes (\c m_ratioFont):
\code
qreal refDpi = 216.;
qreal refHeight = 1776.;
qreal refWidth = 1080.;
QRect rect = qApp->primaryScreen()->geometry();
qreal height = qMax(rect.width(), rect.height());
qreal width = qMin(rect.width(), rect.height());
qreal dpi = qApp->primaryScreen()->logicalDotsPerInch();
m_ratio = qMin(height/refHeight, width/refWidth);
m_ratioFont = qMin(height*refDpi/(dpi*refHeight), width*refDpi/(dpi*refWidth));
\endcode
For a reasonable scaling ratio, the height and width values must be set
according to the default orientation of the reference device, which in this
case is the portrait orientation.
The following code snippet sets the font scaling ratio to \c 1 if it would
be less than one and thus cause the font sizes to become too small:
\code
int tempTimeColumnWidth = 600;
int tempTrackHeaderWidth = 270;
if (m_ratioFont < 1.) {
m_ratioFont = 1;
\endcode
You should experiment with the target devices to find edge cases that
require additional calculations. Some screens might just be too short or
narrow to fit all the planned content and thus require their own layout. For
example, you might need to hide or replace some content on screens with
atypical aspect ratios, such as 1:1.
The scaling ratio can be applied to all sizes in a QQmlPropertyMap to
scale images, fonts, and margins:
\code
m_sizes = new QQmlPropertyMap(this);
m_sizes->insert(QLatin1String("trackHeaderHeight"), QVariant(applyRatio(270)));
m_sizes->insert(QLatin1String("trackHeaderWidth"), QVariant(applyRatio(tempTrackHeaderWidth)));
m_sizes->insert(QLatin1String("timeColumnWidth"), QVariant(applyRatio(tempTimeColumnWidth)));
m_sizes->insert(QLatin1String("conferenceHeaderHeight"), QVariant(applyRatio(158)));
m_sizes->insert(QLatin1String("dayWidth"), QVariant(applyRatio(150)));
m_sizes->insert(QLatin1String("favoriteImageHeight"), QVariant(applyRatio(76)));
m_sizes->insert(QLatin1String("favoriteImageWidth"), QVariant(applyRatio(80)));
m_sizes->insert(QLatin1String("titleHeight"), QVariant(applyRatio(60)));
m_sizes->insert(QLatin1String("backHeight"), QVariant(applyRatio(74)));
m_sizes->insert(QLatin1String("backWidth"), QVariant(applyRatio(42)));
m_sizes->insert(QLatin1String("logoHeight"), QVariant(applyRatio(100)));
m_sizes->insert(QLatin1String("logoWidth"), QVariant(applyRatio(286)));
m_fonts = new QQmlPropertyMap(this);
m_fonts->insert(QLatin1String("six_pt"), QVariant(applyFontRatio(9)));
m_fonts->insert(QLatin1String("seven_pt"), QVariant(applyFontRatio(10)));
m_fonts->insert(QLatin1String("eight_pt"), QVariant(applyFontRatio(12)));
m_fonts->insert(QLatin1String("ten_pt"), QVariant(applyFontRatio(14)));
m_fonts->insert(QLatin1String("twelve_pt"), QVariant(applyFontRatio(16)));
m_margins = new QQmlPropertyMap(this);
m_margins->insert(QLatin1String("five"), QVariant(applyRatio(5)));
m_margins->insert(QLatin1String("seven"), QVariant(applyRatio(7)));
m_margins->insert(QLatin1String("ten"), QVariant(applyRatio(10)));
m_margins->insert(QLatin1String("fifteen"), QVariant(applyRatio(15)));
m_margins->insert(QLatin1String("twenty"), QVariant(applyRatio(20)));
m_margins->insert(QLatin1String("thirty"), QVariant(applyRatio(30)));
\endcode
The functions in the following code snippet apply the scaling ratio to
fonts, images, and margins:
\code
int Theme::applyFontRatio(const int value)
{
return int(value * m_ratioFont);
}
int Theme::applyRatio(const int value)
{
return qMax(2, int(value * m_ratio));
}
\endcode
This technique gives you reasonable results when the screen sizes of the
target devices do not differ too much. If the differences are huge, consider
creating several different layouts with different reference values.
\section1 Loading Files Depending on Platform \section1 Loading Files Depending on Platform
You can use the QQmlFileSelector to apply a QFileSelector to QML file You can use the QQmlFileSelector to apply a QFileSelector to QML file
...@@ -197,10 +437,34 @@ ...@@ -197,10 +437,34 @@
If you need a more dynamic solution for loading parts of your UI on demand, If you need a more dynamic solution for loading parts of your UI on demand,
you can use a Loader. you can use a Loader.
The target platforms might automate the loading of alternative resources for
different display densities in various ways. On iOS, the \e @2x filename
suffix is used to indicate high DPI versions of images. The \l Image QML
type and the QIcon class automatically load @2x versions of images and icons
if they are provided. The QImage and QPixmap classes automatically set the
\c devicePixelRatio of @2x versions of images to \c 2, but you need to add
code to actually use the @2x versions:
\code
if ( qApp->primaryScreen()->devicePixelRatio() >= 2 ) {
imageVariant = "@2x";
} else {
imageVariant = "";
}
\endcode
Android defines generalized screen sizes (small, normal, large, xlarge) and
densities (ldpi, mdpi, hdpi, xhdpi, xxhdpi, and xxxhdpi) for
which you can create alternative resources. Android detects the current
device configuration at runtime and loads the appropriate resources for your
application. However, beginning with Android 3.2 (API level 13), these size
groups are deprecated in favor of a new technique for managing screen sizes
based on the available screen width.
\section1 Loading Components on Demand \section1 Loading Components on Demand
A \l{Loader} can load a QML file (using the source property) or a Component A \l{Loader} can load a QML file (using the \c source property) or a Component
object (using the sourceComponent property). It is useful for delaying the object (using the \c sourceComponent property). It is useful for delaying the
creation of a component until it is required. For example, when a component creation of a component until it is required. For example, when a component
should be created on demand, or when a component should not be created should be created on demand, or when a component should not be created
unnecessarily for performance reasons. unnecessarily for performance reasons.
...@@ -271,7 +535,7 @@ ...@@ -271,7 +535,7 @@
\list \list
\li What if you have a single page that looks completely \li What if you have a single page that looks completely
different between landscape and portrait, i.e. all of the different between landscape and portrait, that is, all of the
child items are different? For each page, have two child child items are different? For each page, have two child
components, with separate layout definitions, and make one components, with separate layout definitions, and make one
or other of the items have zero opacity in each state. You or other of the items have zero opacity in each state. You
......
doc/src/images/scalability-gridlayout.png

6.63 KB

Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment