Layouts, ListViews, and Cards

Figuring out the different ways of placing things on a page

Laying out your content

Now that we understand how pages work, it is time to add stuff to them. We will be going through a number of important layout components and elements that will be useful when designing our app.

By the end of this section you'll have a neat-looking app.

ListViews

If you've ever used Discoverarrow-up-right, NeoChatarrow-up-right, or Plasma's System Settings, you will have come across a ListViewarrow-up-right. Quite simply, it lets you display data on a list.

pageStack.initialPage: Kirigami.ScrollablePage {
    // ...
    Kirigami.CardsListView {
       id: cardsView
        model: kountdownModel
        delegate: kountdownDelegate
    }
}

That seems cryptic, but don't worry. Let's start from the beginning.

We add this component inside our Kirigami.ScrollablePagearrow-up-right from the last tutorial.

We're using Kirigami.CardsListViewarrow-up-right, which is a ListViewarrow-up-right that allows us to easily display cards in a list. However, ListViews are made to show data taken from a model - to automatically populate itself from a set of data that we point it to. That's where the model property comes in: in this example, it's pointing to kountdownModel.

Model

We add our kountdownModel inside the Kirigami.ApplicationWindowarrow-up-right from the last tutorial.

A model defines the way that a data entry is structured. Our kountdownModel will consist of only one element for now. By looking at our ListElementarrow-up-right above, we can see how the data of our kountdownModel are structured: it contains a name, a description, and a date. This isn't set in stone, and you may have different sorts of data in your model. The first two are just strings, and the third is a number we're using as a placeholder.

circle-info

Note

Since QML is built on top of JavaScript, many of this language's features are available for use in QML files. However, QML variables have to be prefixed with property, unless it is inside a JS code block. You can read more about it in this pagearrow-up-right.

Models are also useful in how they can be modified through the use of several methods. Some important ones are:

Delegates

While our kountdownModel contains the data that will be displayed, our kountdownDelegate will handle how the data will be displayed in the ListViewarrow-up-right. For that we use a Kirigami.CardsListViewarrow-up-right designed to display card-type delegates, and those delegates will be visually represented by means of a Kirigami.AbstractCardarrow-up-right.

Delegates automatically receive the properties of the ListElementsarrow-up-right that we have specified in our model. We can therefore just refer to their name, description, and date properties as if they were conventional variables within our delegate.

Building the delegate card

The Componentarrow-up-right that will represent our delegate can be added inside our Kirigami.ApplicationWindowarrow-up-right. We will then check what each part of our delegate component does.

implicitWidth and implicitHeight

The first part we will take a look at is how to manage the width and height of our component:

Looking at our Kirigami.AbstractCardarrow-up-right, the first properties we set are implicitWidtharrow-up-right and implicitHeightarrow-up-right. We have set these to the delegateLayout.implicitWidth and delegateLayout.implicitHeight, i.e. the implicitWidth and implicitHeight of the GridLayout element.

Implicit widths and heights are properties available in any Itemarrow-up-right that function as hints and are set as a default, or as a fallback, if there is no explicit width or height set for these components. These values default to 0x0, so it is very important that you define those in raw Item components as done above.

Here we have set the implicitWidth and implicitHeight of our Kirigami.AbstractCardarrow-up-right to that of the GridLayoutarrow-up-right below to ensure it does not spill out of the card. This way, the card takes as much space is necessary for its contents.

Layouts

The GridLayoutarrow-up-right is inside the Itemarrow-up-right component we have provided for the property contentItemarrow-up-right. This is the Itemarrow-up-right that contains what will be displayed in your card.

We also need to choose a layoutarrow-up-right for our components so that they don't just pile on top of each other. There are three main types that we can choose from:

With ColumnLayoutarrow-up-right and RowLayoutarrow-up-right, all we have to do is write our components inside the Layout component. As you can see, we went with a GridLayoutarrow-up-right, which entails a bit more handiwork.

The first thing you see is our anchors. QtQuick's anchoring systemarrow-up-right provides a useful way of making sure your components are positioned in certain parts of a parent component. We have anchored our GridLayoutarrow-up-right to the left, top, and right of the parent card, ensuring our content stretches across the whole card.

Next we specify the spacing between the rows and columns within our grid, so that our components don't bunch up. Kirigami provides a number of handy predefined unitsarrow-up-right to use for this purpose:

Kirigami Unit
Pixels

smallSpacing

4px

largeSpacing

8px

gridUnit

18px

circle-info

Note

KDE's Visual Design Group (VDG) has a lot more information about the different units defined within Plasma and Kirigami on the Human Interface Guidelinesarrow-up-right.

As you might remember, root is the id of our Kirigami.ApplicationWindowarrow-up-right. It provides the wideScreenarrow-up-right property, used to determine whether the current device screen is a widescreen (i.e. a computer monitor or a phone in landscape). We use a ternary conditionalarrow-up-right here to vary the number of columns in our grid depending on the screen we are using: if it's a widescreen, the grid will have 4 columns, else it will have 2.

Inner components

We could just create three labels within our delegate component and call it a day, but that wouldn't look particularly nice. We'll make use of a few more convenient components:

How the custom Card looks like

Our app so far

chevron-rightMain.qml:hashtag
Screenshot of the app appearance after completing this lesson

So there is our basic card!

With these steps, we have now laid the basic groundwork for adding all the functionality to our app.

Last updated