- Qt 5.3
- Scalability
- Qt 5.3.2 Reference Documentation

# Scalability

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 with different screen configurations: size, density, orientation, resolution, and aspect ratio.

You need to consider scalability when:

- You want to deploy your application to more than one device platform, such as Android, BlackBerry, and iOS, or more than one device screen configuration or form factor.
- Your want to be prepared for new devices that might appear on the market after your initial deployment.

To implement scalable applications using Qt Quick:

- Design UIs using Qt Quick Controls that provide a set of UI controls.
- Define layouts using Qt Quick Layouts, which can resize their items.
- Use property binding to implement use cases not covered by the layouts. For example, to display alternative versions of images on screens with low and high pixel density or automatically rotate view contents according to the current screen orientation.
- Load platform-specific assets using file selectors.
- Load components on demand by using a Loader.

Consider an application that has to be deployed to devices that have different screen configurations, form factors, or UI conventions. There are some patterns that you might consider when designing your application:

- The contents of a view might be quite similar on all screen sizes, but with an expanded content area. If you use the ApplicationWindow QML type from Qt Quick Controls, it will automatically calculate the window size based on the sizes of its content items. If you use Qt Quick Layouts to position the content items, they will automatically resize the items pushed to them.
- The contents of an entire page in a smaller device could form a component element of a layout in a larger device. Therefore, consider making that a separate component (that is, defined in a separate QML file), and in the smaller device, the view will simply contain an instance of that component. On the larger device, there may be enough space to use loaders to show additional items. For example, in an 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 side.
- The screen size and form factors of two devices might be quite similar, but the UI conventions might be totally different.

## Resizing Screens Dynamically

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 item of your application. The ApplicationWindow adds convenience for positioning other controls, such as MenuBar, ToolBar, and StatusBar in a platform independent manner. The ApplicationWindow uses the size constraints of the content items as input when calculating the effective size constraints of the actual window.

In addition to controls that define standard parts of application windows, controls are provided for creating views and menus, as well as presenting or receiving input from users. You can use Qt Quick Controls Styles to apply custom styling to the predefined controls.

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 use Qt Quick Layouts.

## Laying out Screens Dynamically

Qt Quick Layouts provide ways of laying out screen controls in a row, column, or grid, using the RowLayout, ColumnLayout, and GridLayout QML types. The properties for these QML types hold their layout direction and spacing between the cells.

You can use the Layout QML type to attach additional properties to the items pushed to the layouts. For example, you can specify mininum, maximum, and preferred values for item height, width, and size.

The layouts ensure that your UIs are scaled properly when windows and screens are resized and always use the maximum amount of space available.

Constantly resizing and recalculating screens comes with a performance cost. 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 you run into performance problems when using layouts, consider using some other methods, such as bindings, instead.

Here are some things not to do with layouts:

- Do not have bindings to the x, y, width, or height properties of items in a Layout, since this would conflict with the goal of the Layout, and also cause binding loops.
- Do not define complex JavaScript functions that are regularly evaluated. This will cause poor performance, particularly during animated transitions.
- Do not make assumptions about the container size, or about the size of child items. Try to make flexible layout definitions that can absorb changes in the available space.
- Do not use layouts if you want the design to be pixel perfect. Content items will be automatically resized and positioned depending on the space available.

## Handling Pixel Density

If Qt Quick Layouts do not fit your needs, you can fall back to using property binding. Binding enables objects to automatically update their properties in response to changing attributes in other objects or the occurrence of some external event.

When an object's property is assigned a value, it can either be assigned a static value, or bound to a JavaScript expression. In the former case, the property's value will not change unless a new value is assigned to the property. In the latter case, a property binding is created and the property's value is automatically updated by the QML engine whenever the value of the evaluated expression changes.

This type of positioning is the most highly dynamic. However, constantly evaluating JavaScript expressions comes with a performance cost.

For example, bindings are a good way to handle low and high pixel density. The following code snippet uses the Screen.logicalPixelDensity attached property to specify different images to display on screens with low, high, or normal pixel density:

    Image {
        source: {
            if (Screen.logicalPixelDensity < 40)
            "image_low_dpi.png"
            else if (Screen.logicalPixelDensity > 300)
            "image_high_dpi.png"
            else
            "image.png"
            }
        }

## Loading Files Depending on Platform

You can use the QQmlFileSelector to apply a QFileSelector to QML file loading. This enables you to load altenative resources depending on the platform on which the application is run. For example, you can use the `+android` and `+blackberry` file selectors to load different image files when run on Android and BlackBerry devices.

You can use file selectors together with singleton objects to access a single instance of an object on a particular platform.

File selectors are static and enforce a file structure where platform-specific files are stored in subfolders named after the platform. If you need a more dynamic solution for loading parts of your UI on demand, you can use a Loader.

## Loading Components on Demand

A Loader can load a QML file (using the source property) or a Component object (using the sourceComponent property). It is useful for delaying the 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 unnecessarily for performance reasons.

You can also use loaders to react to situations where parts of your UI are not needed on a particular platform, because the platform does not support some functionality. Instead of displaying a view that is not needed on the device the application is running on, you can determine that the view is hidden and use loaders to display something else in its place.

## Switching Orientation

The Screen.orientation attached property contains the current orientation of the screen, from the accelerometer (if available). On a desktop computer, this value typically does not change.

If `primaryOrientation` follows `orientation`, it means that the screen automatically rotates all content that is displayed, depending on how you hold the device. If orientation changes even though `primaryOrientation` does not change, the device might not rotate its own display. In that case, you may need to use Item.rotation or Item.transform to rotate your content.

Application top-level page definitions and reusable component definitions should use one QML layout definition for the layout structure. This single definition should include the layout design for separate device orientations and aspect ratios. The reason for this is that performance during an orientation switch is critical, and it is therefore a good idea to ensure that all of the components needed by both orientations are loaded when the orientation changes.

On the contrary, you should perform thorough tests if you choose to use a Loader to load additional QML that is needed in separate orientations, as this will affect the performance of the orientation change.

In order to enable layout animations between the orientations, the anchor definitions must reside within the same containing component. Therefore the structure of a page or a component should consist of a common set of child components, a common set of anchor definitions, and a collection of states (defined in a StateGroup) representing the different aspect ratios supported by the component.

If a component contained within a page needs to be hosted in numerous different form factor definitions, then the layout states of the view should depend on the aspect ratio of the page (its immediate container). Similarly, different instances of a component might be situated within numerous different containers in a UI, and so its layout states should be determined by the aspect ratio of its parent. The conclusion is that layout states should always follow the aspect ratio of the direct container (not the "orientation" of the current device screen).

Within each layout State, you should define the relationships between items using native QML layout definitions. See below for more information. During transitions between the states (triggered by the top level orientation change), in the case of anchor layouts, AnchorAnimation elements can be used to control the transitions. In some cases, you can also use a NumberAnimation on e.g. the width of an item. Remember to avoid complex JavaScript calculations during each frame of animation. Using simple anchor definitions and anchor animations can help with this in the majority of cases.

There are a few additional cases to consider:

- What if you have a single page that looks completely different between landscape and portrait, i.e. all of the child items are different? For each page, have two child components, with separate layout definitions, and make one or other of the items have zero opacity in each state. You can use a cross-fade animation by simply applying a NumberAnimation transition to the opacity.
- What if you have a single page that shares 30% or more of the same layout contents between portrait and landscape? In that case, consider having one component with landscape and portrait states, and a collection of separate child items whose opacity (or position) depends on the orientation state. This will enable you to use layout animations for the items that are shared between the orientations, whilst the other items are either faded in/out, or animated on/off screen.
- What if you have two pages on a handheld device that need to be on screen at the same time, for example on a larger form factor device? In this case, notice that your view component will no longer be occupying the full screen. Therefore it's important to remember in all components (in particular, list delegate items) should depend on the size of the containing component width, not on the screen width. It may be necessary to set the width in a Component.onCompleted() handler in this case, to ensure that the list item delegate has been constructed before the value is set.
- What if the two orientations take up too much memory to have them both in memory at once? Use a Loader if necessary, if you cannot keep both versions of the view in memory at once, but beware performance on the cross-fade animation during layout switch. One solution could be to have two "splash screen" items that are children of the Page, then you cross fade between those during rotation. Then you can use a Loader to load another child component that loads the actual model data to another child Item, and cross-fade to that when the Loader has completed.