Layouter, listvyer och kort
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.
Vi lägger till komponenten inne i vår Kirigami.ScrollablePage från den tidigare handledningen.
Vi använder Kirigami.CardsListView som är en ListView som enkelt låter oss visa kort i en lista. Dock är listvyer gjorda för att visa data tagen från en modell, för att automatiskt befolkas från en uppsättning data som vi pekar den på. Det är där egenskapen model
kommer in: i det här exemplet pekar den på 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
}
}
// ...
}
Vi lägger till vår kountdownModel
inne i Kirigami.ApplicationWindow från den tidigare handledningen.
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.
Anmärkning
Eftersom QML är byggt på Javascript är många av språkets funktioner tillgängliga för användning i QML-filer. QML-variabler måste dock ha prefixetproperty
, såvida de inte finns i ett JS-kodblock. Du kan läsa mer om det på den här sidan.Modeller är också användbara på det sätt de kan ändras genom användning av flera metoder. Några viktiga är:
- ListModel.append(yourobject: jsobject) lägger till ett Javascript-objekt (JSObject)
yourobject
i listmodellen, och placerar det efter det sista objektet i modellen. För att det ska göras korrekt, måste du tillhandahålla ett JSObject med rätt egenskaper och motsvarande datatyper. - ListModel.get(index: int) returnerar JSObject på indexplatsen du tillhandahåller.
- ListModel.remove(index: int, count: int) tar bort JSObject på den tillhandahållna platsen
index
, och så många efter den platsen som du anger icount
(1 inkluderar bara JSObject på tillhandahållet index) - ListModel.set(index: int, yourobject: jsobject) ändrar objektet på tillhandahållen plats
index
med värdet som tillhandahålls iyourobject
. Samma regel som med.append
.
Delegater
Medan vår kountdownModel
innehåller data som ska visas, hanterar vår kountdownDelegate
hur data visas i ListView. För att göra det använder vi en Kirigami.CardsListView konstruerad för att visa delegater av korttyp, och delegaterna representeras visuellt med hjälp av ett 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
Den Component som representerar vår delegat kan läggas till inne i vårt Kirigami.ApplicationWindow. Vi tittar sedan på vad varje del av vår delegatkomponent gör.
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 {
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")
// 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
// ...
}
}
}
Om vi betraktar vår Kirigami.AbstractCard, är den första egenskaperna vi ställer in implicitWidth och implicitHeight. Vi har ställer in dem till delegateLayout.implicitWidth
och delegateLayout.implicitHeight
, dvs. implicitWidth
och implicitHeight
i elementet GridLayout
.
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.
Här har vi ställt in implicitWidth
och implicitHeight
i vår Kirigami.AbstractCard till det i vår GridLayout nedan, för att säkerställa att den inte flyter ut utanför kortet. På så sätt upptar kortet så mycket utrymme som är nödvändigt för dess innehåll.
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.
Därefter anger vi mellanrummet mellan raderna och kolumnerna i vårt rutnät, så att våra komponenter inte trycks ihop. Kirigami tillhandahåller ett antal praktiska fördefinierade enheter att använda i detta syfte:
Kirigami-enhet | Bildpunkter |
---|---|
smallSpacing | 4 bildpunkter |
largeSpacing | 8 bildpunkter |
gridUnit | 18 bildpunkter |
Anmärkning
KDE's visuella designgrupp (VDG) har mycket mer information om de olika enheterna definierade inom Plasma och Kirigami i Human Interface Guidelines.Som du kanske minns är root
identifieraren för vårt Kirigami.ApplicationWindow. Den tillhandahåller egenskapen wideScreen, som används för att avgöra om den aktuella enhetens skärm är en bred skärm (dvs. en datorskärm eller en telefon med liggande orientering). Vi använder ett ternärt villkor här för att variera antalet kolumner i vårt rutnät beroende på vilken skärm vi använder: om det är en bred skärm har rutnätet fyra kolumner, annars har det två.
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")
}
}
- Vänster, Kirigami.Heading: använder
date
iListElement
som första nivåns rubrik. - Mitten, ColumnLayout: Har en Kirigami.Heading som visar aktivitetsnamnet, en Kirigami.Separator som tillhandahåller den horisontella linjen, och en Controls.Label som visar en uppgifts valfria beskrivning. De senare två komponenterna har egenskapen visible som kontrollerar om beskrivningen är tom eller inte och visar komponenten beroende på resultatet av
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:
|
|
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.