QML Notes
Resently update Qt to version 5.12.
While review code I started getting QML Warnings about using Anchors inside Layouts.
Detected anchors on an item that is managed by a layout. This is undefined behavior; use Layout.alignment instead.
After some investigation it became clear that issues exist with mixing the three possible methods of component positioning (Manual, Anchors and Layouts) and this can result in complex code and unexpected behaviour.
Hence these notes.
1. Mixing Layouts and Anchors
Just don’t do it.
While the above warning can be eliminated when using Anchors inside a Layout Component by putting the anchored components inside a non-layout component ( i.e. Rectange or Item ) with the wrapping component positioned ( normally to the dimensions of the outer Layout component with Layout.fillHeight, Layout.fillWidth) with Layout Properties, the resulting positioning still results in unexpected behaviour.
Obviously a Layout component can be used inside an Anchor component but still with confusing results.
One of the main issues is that mixing seems to cause non-local positional changes that are hard to reason about. For example I found that a single anchored position deep inside the layout can cause dimension and alignment changes to the overall form. Changing that anchored positioning can result in a cascade of positional changes requiring a series of fine changes to correct. This results in a highly complex and unclear positioning environment.
2. Simplicity is better than Fine Detail
While it is possible to do some very fine detail positioning it is differcult to control particularly when switching from portrait to landscape or changing aspect ratios. Layouts are generally simpler than Anchors but simplifying the overall positioning can also be a benefical approach.
3. Avoid using Rectangle or Item components
In most cases Rectangle or Item components require some non-layout positioning which can lead to hard to reason behaviour. In general they can be replaced by an appropriate Layout component, either Row, Column or Grid, which self adjust more readily. As a result Item components should rarely (never?) be used and Rectangles be used to provide features that are lacking in Layout components such as color. Frame components usable should be similar to Rectangles.
The following (untested) code is a suggested way of combining a Rectangle/Frame and an Layout component.
Rectangle
{
default property alias data: grid.data
implicitWidth: grid.implicitWidth
implicitHeight: grid.implicitHeight
GridLayout
{
anchors.fill: parent
}
}
4. Non-visible Component do not impact on positioning
At least in the case Layout components, when they are not visible they have no effect on positioning. This means that when different positioning is required for different statuses ( Portrait/Landscape) it is better to duplicate components in separate simplified layouts and hide the inactive layouts.
5. Avoid fixed Heights and Widths
It is better to let the positioning algorithm sort out heights and widths than fixing them even if with calculation. The need to use fixed values is a smell and alternatives should be prefered. Margins are less smelly but large values may cause positioning conflicts and should be used with caution.
6. Layout.alignment property is ambiguous
The documentation is unclear.
This property allows you to specify the alignment of an item within the cell(s) it occupies.
Tests indicate however that Layout.alignment is set for the outer Layout component MAY apply to all of the contained/child components. Under SOME circumstances the child components may also require their alignments set. Why this is so needs further investigation.
7. All other Layout Properties apply only to the component itself
All Layout properties other than alignment apply to the individual component, either Layout or Anchor. So for example to make all components in an outer layout fill the width Layout.fillWidths required in each component.
8. Margins are outside the component
Setting a Layout margin has effect outside the component. So a margin position the individual component rather than the position of any contained component. Setting a margin on an outer component ( i.e ColumnLayout) may appear to offset the contained components but in fact offsets the outer component itself.
9. Margins are not hidden
When a margin is used to provide separation between two components the margin is still included even if the component is hidden. This would seem to be a bug?
When applying a margin to a potentially hidden component a test is required.
Layout.leftMargin : visible ? 10 : 0
10. Layout Spacings are not hidden
As for margins the spacing property is still included when a component is hidden. This may be more logical as its value can be applied multiple times.
If hidden components are required in a Layout avoid spacing and use the appropriate tested Margins.