1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
|
/*
* Copyright 2013 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*!
\qmlmodule Lomiri.Layouts 1.0
\title Layouts
*/
/*!
\page lomiri-layouts.html
\title Layouts - Introduction
\nextpage Layouts - Terminology
QML has the following basic layout primitives:
\list
\li \l {https://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick2-column.html}{Column} - arrange children in a column
\li \l {https://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick2-row.html}{Row} - arrange children in a row
\li \l {https://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick2-grid.html}{Grid} - arrange children in a grid of x columns and y rows
\li \l {https://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick2-flow.html}{Flow} - arrange children side-by-side with wrapping
\endlist
\raw HTML
<br>
\endraw
Unfortunately in a design that needs to work in many different form factors these
aren't very flexible on their own as:
\list 1
\li not designed to alter size of children - so no form of stretching
supported by default.
\li as a result no way to have contents fill the container (without
calculating the width/height of the children manually).
\endlist
\raw HTML
<br>
\endraw
As a result, most applications need to do calculations to size the children
correctly in these primitives to fill the whole container.
Qt offers advice to developers on multi-layouts in QML. In summary they recommend:
\e {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 container Aspect Ratios.}
UIs layouts should be constructed to share as many components as possible. Then on display
mode change these shared components can be reparented, reducing number of components to
unload/reload and also helping to save state.
Using a Loader to switch the QML for different display modes is slower, and will involve
loss of state. Instead the above advice is to use AnchorChanges & PropertyChanges to specify
all layouts in one QML document, so switching display mode is dynamic - but admittedly is
a painful for all display modes and states that an application may want to support.
\l {http://doc-snapshot.qt-project.org/qt5-stable/qtquicklayouts/qmlmodule-qtquick-layouts1-qtquick-layouts-1-0.html}
{QtQuick Controls} introduces the \l {http://doc-snapshot.qt-project.org/qt5-stable/qtquicklayouts/qml-qtquick-layouts1-columnlayout.html}
{ColumnLayout}, \l {http://doc-snapshot.qt-project.org/qt5-stable/qtquicklayouts/qml-qtquick-layouts1-rowlayout.html}{RowLayout}
and \l {http://doc-snapshot.qt-project.org/qt5-stable/qtquicklayouts/qml-qtquick-layouts1-gridlayout.html}{GridLayout}
components as well as the \l{http://doc-snapshot.qt-project.org/qt5-stable/qtquicklayouts/qml-qtquick-layouts1-layout.html}{Layout}
attached properties, which brings additional layouting possibilities to Qt Quick.
In addition to these, UI toolkit had introduced the Lomiri.Layouts module to help developers
define different layouts for different orientations and form factors, all being possible
to be done within the same code base.
This tutorial gives an introduction to layout factoring abilities offered by
Lomiri UI toolkit. It tries to cover few possible layout scenarios, however will
not cover advanced scenarios application developers may need.
Tutorial chapters:
\list 1
\li \l {Layouts - Terminology}{Terminology}
\li \l {Layouts - The first conditional layout}{The first conditional layout}
\li \l {Layouts - Changing the order}{Changing the order}
\li \l {Layouts - Lay out a single item differently from others}{Lay out a single item differently from others}
\li \l {Layouts - Hiding elements, showing more}{Hiding elements, showing more}
\li \l {Layouts - Overlay items in an item host}{Overlay items in an item host}
\li \l {Layouts - Defining more layouts for different form factors}{Defining more layouts for different form factors}
\endlist
So, let's take them step-by-step...
*/
/*!
\page lomiri-layouts1.html
\title Layouts - Terminology
\nextpage Layouts - The first conditional layout
First let's introduce the terminology we are going to use across this tutorial.
\section3 Layout Block, Container and Item holder
A layout block is a component embedding several layout definitions and items to be
laid out. It is typically defined by the \l Layouts component.
Each layout defined in the block is compound of containers, which can host laid out
items hosted by item holders.
An item holder is a pseudo-item which can host only one item, where the item
is anchored to the item holder's edges, therefore the item holder has control
over the componet's size, scale and rotation.
To understand this let's take the following layout structure:
\image sample-layout.png
In this layout all three buttons are laid out in the same container, but green
button was required to take the height of the window, whereas the red and blue
buttons were required to have the same width and height.
Illustrating the layout on the image with code:
\qml
Layouts { // <-- layout block
id: layouts
layouts: [
// [...]
ConditionalLayout { // <-- layout
name: "composit"
Row { // <-- layout container
// [...]
ItemLayout { // <-- item holder
item: "item2"
// [...]
}
ItemLayout { // <-- item holder
item: "item1"
// [...]
}
ItemLayout { // <-- item holder
item: "item3"
// [...]
}
}
}
]
// the items to lay outitem3
Button {
Layouts.item: "item1"
// [...]
}
Button {
Layouts.item: "item2"
// [...]
}
Button {
Layouts.item: "item3"
// [...]
}
}
\endqml
A container can be any item, however it is preferable to use positioners or QtQuick
layout elements whenever possible.
As next step let's create some layouts.
*/
/*!
\page lomiri-layouts2.html
\title Layouts - The first conditional layout
\nextpage Layouts - Changing the order
As first let's create the following default layout, with anchored buttons to each other.
\image default-layout.png
Defined by the following code:
\snippet layouts/layout1.qml default layout
\section1 Walkthrough
\section2 Import
First of all, in order to use the layouting abilities, you need to import Lomiri.Layouts.
\code
import Lomiri.Layouts 1.0
\endcode
This layout will have the red button anchored to the parent's left, top and bottom, having
a width of 15 grid units. The green and blue buttons are anchored left to the red button,
righ to their parent, top and bottom to the parent top respectively to the parent bottom
and both having a height of 10 grid units.
This layout looks good in small form factors, however as the width, height and grid unit
changes, this layout will start to look cumbersome.
Every component we wan to lay out must be marked. This "marking" is done by attaching the
Layouts.item property to erach item participating in the layouting. Therefore we
mark each button with a unique name, "red", "green" and "blue".
\section2 Define the conditional layout
Let's define a column layout for the case when the layout block width passes 50 GU, and
move the items into a \l{http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick2-row.html}{Row}
container in the following order: "red", "green" and "blue". We also need to specify the
size these components will have, so let's set the width to one third of the container's width
and top and bottom anchored to the row's top and bottom.
\snippet layouts/layout1.qml row layout
Note the way the container is defined. Items are laid out using ItemLayout host items.
The items will be laid out in the order the ItemLayout hosts are declared. Beside this
ItemLayout also drives the size, scale, rotation, availability (enabled) visibility and
opacity of the hosted item.
The conditional layout is given a name so it can be identified when the layout is set
through Layouts.curentLayout property. This, beside debugging abilities, gives additional
possibilities to configure properties that are not directly updated by the layouting.
Combining this with the default layout we will see the following layout when width exceeds
50 GU:
\image layout1.png
\snippet layouts/layout1.qml 0
*/
/*!
\page lomiri-layouts3.html
\title Layouts - Changing the order
\nextpage Layouts - Lay out a single item differently from others
So far we have seen how to define the default layout, a conditional layout and how to place
items into those.
As mentioned in the ConditionalLayout documentation, items hosted by the container are laid
out based on the order they are hosted by the ItemLayout.
So let's change the order the buttons are laid out so that we have blue, red and green
order.
\snippet layouts/layout2.qml row layout
The layout after resizing the window width to exceed 50 GU will look as follows:
\image layout2.png
Note that when resizing the window width to < 50 GU, you will get all your components back to
their original (default) positions and anchors.
*/
/*!
\page lomiri-layouts4.html
\title Layouts - Lay out a single item differently from others
\nextpage Layouts - Hiding elements, showing more
As mentioned, ItemLayout has control over the size, anchors and visibility of the hosted element.
Therefore we can have the blue button with a different size than the other two. Let's have the
blue button's width set to 10 GUs and its height to 10 GUs less than the positioner's height.
The code will look as follows:
\snippet layouts/layout3.qml row layout
\image layout3.png
*/
/*!
\page lomiri-layouts5.html
\title Layouts - Hiding elements, showing more
\nextpage Layouts - Overlay items in an item host
Till this point we know how to define a layout block, what is the default layout, how to
create layout, how to define the container and how to define the hosted elements and how
to define item hosts to lay out individual items.
There can be situations when for certain layouts we don't want to transfer all the components
of a default layout. More, there can be situations when we want to show more components
when we have more space to our disposal. Perhaps we want to provide more functionality when
the phone is turned from portrait to landscape (typical use case is a Calculator application
which on portrait is a simple calculator but on landscape provides scientific calculator
functions). In the following we will define two layouts where we cover both use cases.
\section1 Hiding components
Let's create a layout where we only show the red and green buttons. This can be achieved by
specifying only those components to be hosted by the container.
\snippet layouts/layout6.qml row layout
The layout when the block width exceeds 50 GU will look like this:
\image layout6.png
\section1 Showing more content
Another use case is to show extra content in a different layout/form factor.
These components can simply be declared inside the layout itself, assuming that those are
not going to be used in any other layout. If yes, those must also be declared in the default
layout in order to preserve their state, or other modalities to transfer the component state
must be used.
Let's create a layout which will be activated when the layout block width exceeds 70 GU.
\snippet layouts/layout6.qml flow layout
\image layout6-2.png
*/
/*!
\page lomiri-layouts6.html
\title Layouts - Overlay items in an item host
\nextpage Layouts - Defining more layouts for different form factors
There is one more thing you can do with ItemLayout container, which is to define overlay items
for certain hosted items on certain layouts. If an ItemLayout has child elements defined, the
hosted item will be stacked as topmost element, so all the child elements declared in ItemLayout
will be rendered as overlay on top of the hosted item.
\image layout7.png
\snippet layouts/layout7.qml overlay layout
*/
/*!
\page lomiri-layouts7.html
\title Layouts - Defining more layouts for different form factors
As mentioned, with Layouts we can achieve to have a single code base supporting different form
factors. The following example illustrates how to support different layouts with the same code
base.
\section1 Default layout
\image simple-layout1.png
\snippet layouts/SimpleLayout.qml default layout
\section1 Conditional layouts
\section2 Column layout
\image simple-layout2.png
\snippet layouts/SimpleLayout.qml column
\section2 Row layout
\image simple-layout3.png
\snippet layouts/SimpleLayout.qml row
\section2 Layout hiding element
\image simple-layout4.png
\snippet layouts/SimpleLayout.qml hiding-element
\section2 Layout showing more
\image simple-layout5.png
\snippet layouts/SimpleLayout.qml showing-more
\section1 The entire code
\snippet layouts/SimpleLayout.qml 0
\section1 That's it
You're ready to go. You can find the layouting components under \l Layouting.
For further questions please visit \b #lomiri-app-devel irc channel on freenode.
*/
|