Skip to main content
Skip to content

Rozloženia, ListView a karty

Pochopenie rôznych spôsobov umiestňovania vecí na stránku

Rozloženie vášho obsahu

Teraz, keď rozumieme, ako fungujú stránky, je čas pridať na ne obsah. Prejdeme niekoľkými dôležitými komponentmi rozloženia a prvkami, ktoré budú užitočné pri navrhovaní našej aplikácie.

Na konci tejto sekcie budete mať pekne vyzerajúcu aplikáciu.

ListViews

Ak ste niekedy použili Discover, NeoChat alebo Systémové nastavenia Plasma, stretli ste sa s ListView. Jednoducho povedané, umožňuje vám zobrazovať dáta v zozname.

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

To vyzerá záhadne, ale nebojte sa. Začnime od začiatku.

Tento komponent pridávame do našej Kirigami.ScrollablePage z posledného tutoriálu.

Používame Kirigami.CardsListView, čo je ListView, ktorý nám umožňuje jednoducho zobrazovať karty v zozname. Avšak ListViews sú vytvorené na zobrazovanie dát prevzatých z modelu — na automatické naplnenie sa zo sady dát, na ktorú ich nasmerujeme. Tu prichádza vlastnosť model: v tomto príklade ukazuje na kountdownModel.

Model

Kirigami.ApplicationWindow {
    // ...
    ListModel {
        id: kountdownModel
        // Každý ListElement je prvok v zozname obsahujúci informácie
        ListElement {
            name: "Dog birthday!!"
            description: "Big doggo birthday blowout."
            date: 100
        }
    }
    // ...
}

Pridávame náš kountdownModel do Kirigami.ApplicationWindow z posledného tutoriálu.

Model definuje spôsob, akým je dátový záznam štruktúrovaný. Náš kountdownModel sa zatiaľ bude skladať iba z jedného prvku. Pozrením na náš ListElement vyššie vidíme, ako sú štruktúrované dáta nášho kountdownModel: obsahuje meno, popis a dátum. Toto nie je nemenné a vo vašom modeli môžete mať rôzne druhy dát. Prvé dve sú len reťazce a tretí je číslo, ktoré používame ako zástupný symbol.

Modely sú tiež užitočné v tom, ako sa dajú modifikovať použitím niekoľkých metód. Niektoré dôležité sú:

Delegát

Zatiaľ čo náš kountdownModel obsahuje dáta, ktoré sa zobrazia, náš kountdownDelegate spracuje, ako sa dáta zobrazia v ListView. Na to používame Kirigami.CardsListView navrhnutý na zobrazovanie delegátov typu kariet a tieto delegáty budú vizuálne reprezentované prostredníctvom Kirigami.AbstractCard.

Delegáty automaticky prijímajú vlastnosti inštancií ListElement, ktoré sme špecifikovali v našom modeli. Preto sa môžeme jednoducho odvolávať na ich vlastnosti name, description a date, ako keby to boli bežné premenné v našom delegáte.

Zostavenie delegátovej karty

Komponent Component, ktorý bude reprezentovať náš delegát, sa dá pridať do nášho Kirigami.ApplicationWindow. Potom skontrolujeme, čo robí každá časť nášho komponentu delegáta.

Kirigami.ApplicationWindow {
    // ...
    Component {
        id: kountdownDelegate
        Kirigami.AbstractCard {
            contentItem: Item {
                // implicitWidth/Height definujú prirodzenú šírku/výšku položky, ak nie je
                // špecifikovaná žiadna šírka alebo výška. Nastavenie nižšie definuje preferovanú
                // veľkosť komponentu na základe jeho obsahu
                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: bude hotové... čoskoro!
                    }
                }
            }
        }
    }
    // ...
}

implicitWidth a implicitHeight

Prvou časťou, na ktorú sa pozrieme, je spravovanie šírky a výšky nášho komponentu:

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

Keď sa pozrieme na náš Kirigami.AbstractCard, prvé vlastnosti, ktoré nastavujeme, sú implicitWidth a implicitHeight. Nastavili sme ich na delegateLayout.implicitWidth a delegateLayout.implicitHeight, t.j. implicitWidth a implicitHeight prvku GridLayout.

Implicitné šírky a výšky sú vlastnosti dostupné v akomkoľvek Item, ktoré fungujú ako nápovedy a sú nastavené ako predvolené alebo záložné, ak pre tieto komponenty nie je nastavená žiadna explicitná šírka alebo výška. Tieto hodnoty sú predvolene 0x0, preto je veľmi dôležité, aby ste ich definovali v surových komponentoch Item, ako je to urobené vyššie.

Tu sme nastavili implicitWidth a implicitHeight nášho Kirigami.AbstractCard na hodnoty GridLayout nižšie, aby sme zabezpečili, že sa nevyleje z karty. Takto karta zaberie toľko miesta, koľko je potrebné pre jej obsah.

Rozloženia

GridLayout je vnútri komponentu Item, ktorý sme poskytli pre vlastnosť contentItem. Toto je Item, ktorý obsahuje to, čo sa zobrazí vo vašej karte.

Musíme tiež zvoliť rozloženie pre naše komponenty, aby sa navzájom neprekladali. Existujú tri hlavné typy, z ktorých si môžeme vybrať:

  • ColumnLayout rozloží vaše komponenty vertikálne, v jednom stĺpci
  • RowLayout rozloží vaše komponenty horizontálne, v jednom riadku
  • GridLayout rozloží vaše komponenty v mriežke so zostavou podľa vášho výberu

S ColumnLayout a RowLayout stačí napísať naše komponenty vnútri komponentu Layout. Ako vidíte, rozhodli sme sa pre GridLayout, čo obnáša trochu viac ručnej práce.

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
    // ...
}

Prvá vec, ktorú vidíte, sú naše anchors. Systém ukotvenia QtQuick poskytuje užitočný spôsob, ako zabezpečiť, aby boli vaše komponenty umiestnené v určitých častiach rodičovského komponentu. Ukotvili sme náš GridLayout doľava, hore a doprava rodičovskej karty, čím zabezpečíme, že sa náš obsah roztiahne cez celú kartu.

Ďalej špecifikujeme medzery medzi riadkami a stĺpcami v rámci našej mriežky, aby sa naše komponenty nezhlukovaly. Kirigami poskytuje niekoľko praktických preddefinovaných jednotiek na tento účel:

Jednotka KirigamiPixely
smallSpacing4px
largeSpacing8px
gridUnit18px

Ako si možno pamätáte, root je id nášho Kirigami.ApplicationWindow. Poskytuje vlastnosť wideScreen, používanú na určenie, či je aktuálna obrazovka zariadenia široká (t.j. monitor počítača alebo telefón na šírku). Používame tu ternárny podmienený operátor na zmenu počtu stĺpcov v našej mriežke v závislosti od obrazovky, ktorú používame: ak je široká, mriežka bude mať 4 stĺpce, inak bude mať 2.

Komponenty

Mohli by sme jednoducho vytvoriť tri popisky v rámci nášho komponentu delegáta a bolo by to, ale nevyzeralo by to obzvlášť pekne. Využijeme niekoľko ďalších pohodlných komponentov:

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")
    }
}
Ako vyzerá vlastná karta

Ako vyzerá vlastná karta

  • Vľavo, Kirigami.Heading: používa date z ListElement ako nadpis úrovne 1.
  • V strede, ColumnLayout: má Kirigami.Heading, ktorý zobrazuje názov úlohy; Kirigami.Separator, ktorý poskytuje horizontálnu čiaru; a Controls.Label, ktorý zobrazuje voliteľný popis úlohy. Posledné dva komponenty majú vlastnosť visible, ktorá kontroluje, či je popis prázdny alebo nie, a zobrazuje komponenty v závislosti od výsledku description.length > 0.
  • Vpravo, Controls.Button: tlačidlo, ktoré bude niečo robiť... čoskoro!

Naša aplikácia doteraz

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
        }
    }
}

Screenshot of the app appearance after completing this lesson

Tak tu je naša základná karta!

S týmito krokmi sme položili základný základ pre pridanie všetkej funkčnosti do našej aplikácie.