Skip to main content
Gå till innehåll

Layouter, listvyer och kort

Räkna ut de olika sätten att placera saker på en sida

Placera ut ditt innehåll

Nu när vi förstår hur sidor fungerar, är det dags att lägga till saker på dem. Vi går igenom ett antal viktiga layoutkomponenter och element som är användbara när vi konstruerar vårt program.

I slutet av det här avsnittet har du ett snyggt program.

Listvyer

Om du någonsin har använt Discover, NeoChat eller Plasmas systeminställningar, har du stött på en ListView. Den låter dig helt enkelt visa data i en lista.

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

Det verkar kryptiskt, men oroa dig inte. Låt oss börja från början.

We add this component inside our Kirigami.ScrollablePage from the last tutorial.

We're using Kirigami.CardsListView, which is a ListView 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.

Modell

Kirigami.ApplicationWindow {
    // ...
    ListModel {
        id: kountdownModel
        // Varje ListElement är ett element i listan, och innehåller information
        ListElement {
            name: "Dog birthday!!"
            description: "Big doggo birthday blowout."
            date: 100
        }
    }
    // ...
}

We add our kountdownModel inside the Kirigami.ApplicationWindow from the last tutorial.

En modell definierar sättet som en datapost är strukturerad. Vår kountdownModel består för tillfället bara av ett element. Genom att titta på vårt ListElement ovan, kan vi se hur data i vår kountdownModel är strukturerade: de innehåller ett namn, en beskrivning och ett datum. Det är inte hugget i sten, och du kan ha olika typer av data i din modell. De två första är bara strängar, och den tredje är ett tal som vi använder som platsmarkering.

Modeller är också användbara på det sätt de kan ändras genom användning av flera metoder. Några viktiga är:

Delegater

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

Delegater får automatiskt egenskaperna i ListElements som vi har angivit i vår modell. Vi kan därför bara referera till egenskaperna name, description och date som om de är konventionella variabler inne i vår delegat.

Bygga delegatkortet

The Component that will represent our delegate can be added inside our Kirigami.ApplicationWindow. We will then check what each part of our delegate component does.

Kirigami.ApplicationWindow {
    // ...
    Component {
        id: kountdownDelegate
        Kirigami.AbstractCard {
            contentItem: Item {
                // implicitWidth/Height definierar den naturliga bredd/höjd för ett objekt om ingen
                // bredd eller höjd anges. Inställningen nedan definierar en komponents föredragna
                // storlek baserat på dess innehåll
                implicitWidth: delegateLayout.implicitWidth
                implicitHeight: delegateLayout.implicitHeight
                GridLayout {
                    id: delegateLayout
                    anchors {
                        left: parent.left
                        top: parent.top
                        right: parent.right
                    }
                    rowSpacing: Kirigami.Units.largeSpacing
                    columnSpacing: Kirigami.Units.largeSpacing
                    columns: root.wideScreen ? 4 : 2

                    Kirigami.Heading {
                        level: 1
                        text: date
                    }

                    ColumnLayout {
                        Kirigami.Heading {
                            Layout.fillWidth: true
                            level: 2
                            text: name
                        }
                        Kirigami.Separator {
                            Layout.fillWidth: true
                            visible: description.length > 0
                        }
                        Controls.Label {
                            Layout.fillWidth: true
                            wrapMode: Text.WordWrap
                            text: description
                            visible: description.length > 0
                        }
                    }
                    Controls.Button {
                        Layout.alignment: Qt.AlignRight
                        Layout.columnSpan: 2
                        text: i18n("Edit")
                        // onClicked: snart klart!
                    }
                }
            }
        }
    }
    // ...
}

implicitWidth och implicitHeight

Den första delen vi tar en titt på är hur komponentens bredd och höjd hanteras:

Kirigami.AbstractCard {
    contentItem: Item {
        implicitWidth: delegateLayout.implicitWidth
        implicitHeight: delegateLayout.implicitHeight
        GridLayout {
            id: delegateLayout
            // ...
        }
    }
}

Looking at our Kirigami.AbstractCard, the first properties we set are implicitWidth and implicitHeight. We have set these to the delegateLayout.implicitWidth and delegateLayout.implicitHeight, i.e. the implicitWidth and implicitHeight of the GridLayout element.

Implicita bredder och höjder är egenskaper tillgängliga i alla Item som fungerar som tips och ställs in som förvalda värden, eller som reserv om det inte finns någon bredd och höjd inställt för komponenterna. Värdena har förval 0x0, så det är mycket viktigt att de definieras i de obehandlade komponenterna som gjordes ovan.

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

Layouter

GridLayout är inne i komponenten Item vi tillhandahåller för egenskapen contentItem. Det är Item som innehåller det som kommer att visas på kortet.

Vi behöver också välja en layout för våra komponenter så att de inte bara staplas upp på varandra. Det finns tre huvudtyper vi kan välja bland:

  • ColumnLayout placerar ut komponenterna vertikalt, i en enda kolumn
  • RowLayout placerar ut komponenterna horisontellt, i en enda rad
  • GridLayout placerar ut komponenterna i ett rutnät med en sammansättning du väljer

Med ColumnLayout och RowLayout, är allt vi behöver göra är att skriva våra komponenter inne i komponenten Layout. Som du kan se, bestämde vi oss för en GridLayout, vilket medför lite mer hantverk.

GridLayout {
    id: delegateLayout
    anchors {
        left: parent.left
        top: parent.top
        right: parent.right
    }
    rowSpacing: Kirigami.Units.largeSpacing
    columnSpacing: Kirigami.Units.largeSpacing
    columns: root.wideScreen ? 4 : 2
    // ...
}

Det första du ser är våra anchors. Förankringssystemet i QtQuick är ett användbart sätt att säkerställa att komponenterna är placerade på vissa ställen i en överliggande komponent. Vi har förankrat vår GridLayout till vänster, överst och till höger om det överliggande kortet, vilket säkerställer att vårt innehåll sträcker sig över hela kortet.

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 units to use for this purpose:

Kirigami-enhetBildpunkter
smallSpacing4 bildpunkter
largeSpacing8 bildpunkter
gridUnit18 bildpunkter

As you might remember, root is the id of our Kirigami.ApplicationWindow. It provides the wideScreen 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 conditional 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.

Inre komponenter

Vi skulle kunna bara skapa tre beteckningar inne i vår delegatkomponent och låta det vara nog, men det skulle inte se särskilt snyggt ut. Vi utnyttjar några ytterligare praktiska komponenter:

GridLayout {
    // ...
    Kirigami.Heading {
        Layout.fillHeight: true
        level: 1
        text: date
    }

    ColumnLayout {
        Kirigami.Heading {
            Layout.fillWidth: true
            level: 2
            text: name
        }

        Kirigami.Separator {
            Layout.fillWidth: true
            visible: description.length > 0
        }

        Controls.Label {
            Layout.fillWidth: true
            wrapMode: Text.WordWrap
            text: description
            visible: description.length > 0
        }
    }

    Controls.Button {
        Layout.alignment: Qt.AlignRight
        Layout.columnSpan: 2
        text: i18n("Edit")
    }
}
Hur ett eget Card ser ut

Hur ett eget Card ser ut

  • Left, Kirigami.Heading: uses the ListElement's date as a level 1 heading.
  • Middle, ColumnLayout: has a Kirigami.Heading that displays the task name; a Kirigami.Separator, which provides the horizontal line; and a Controls.Label, that displays a task's optional description. The latter two components have a visible property, which checks if the description is empty or not and displays the components depending on the result of description.length > 0.
  • Höger, Controls.Button: en knapp som kommer att göra någonting... snart!

Vårt program så långt

Main.qml:
 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
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

Kirigami.ApplicationWindow {
    id: root

    width: 400
    height: 300

    title: i18nc("@title:window", "Day Kountdown")

    // ListModel needed for ListView, contains elements to be displayed
    ListModel {
        id: kountdownModel
        // Each ListElement is an element on the list, containing information
        ListElement {
            name: "Dog birthday!!"
            description: "Big doggo birthday blowout."
            date: 100
        }
    }

    Component {
        id: kountdownDelegate
        Kirigami.AbstractCard {
            contentItem: Item {
                implicitWidth: delegateLayout.implicitWidth
                implicitHeight: delegateLayout.implicitHeight
                GridLayout {
                    id: delegateLayout
                    anchors {
                        left: parent.left
                        top: parent.top
                        right: parent.right
                    }
                    rowSpacing: Kirigami.Units.largeSpacing
                    columnSpacing: Kirigami.Units.largeSpacing
                    columns: root.wideScreen ? 4 : 2

                    Kirigami.Heading {
                        // Level determines the size of the heading
                        level: 1
                        text: date
                    }

                    // Layout for positioning elements vertically
                    ColumnLayout {
                        Kirigami.Heading {
                            Layout.fillWidth: true
                            level: 2
                            text: name
                        }
                        // Horizontal rule
                        Kirigami.Separator {
                            Layout.fillWidth: true
                            visible: description.length > 0
                        }
                        // Labels contain text
                        Controls.Label {
                            Layout.fillWidth: true
                            // Word wrap makes text stay within box and shift with size
                            wrapMode: Text.WordWrap
                            text: description
                            visible: description.length > 0
                        }
                    }
                    Controls.Button {
                        Layout.alignment: Qt.AlignRight
                        // Column spanning within grid layout (vertically in this case)
                        Layout.columnSpan: 2
                        text: i18n("Edit")
                        //onClicked: to be done...
                    }
                }
            }
        }
    }

    pageStack.initialPage: Kirigami.ScrollablePage {
        title: i18nc("@title", "Kountdown")

        // List view for card elements
        Kirigami.CardsListView {
            id: cardsView
            // Model contains info to be displayed
            model: kountdownModel
            // Delegate is how the information will be presented in the ListView
            delegate: kountdownDelegate
        }
    }
}

Skärmbild av programmets utseende efter att ha gjort färdigt den här lektionen

Så där är vårt grundläggande kort.

Med de här stegen har vi nu lagt grundstenen för att lägga till alla funktioner i vårt program.