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 i våran. Vi går igenom ett antal viktiga layoutkomponenter och element som är användbara när vi konstruerar vårt program.
Bli inte rädd för de stora kodstyckena. Vi går igenom allting som vi inte har täckt tidigare, och i slutet av avsnittet kommer du att ha ett snyggt program.
Listvyer
Om du någonsin har använt Discover, NeoChat eller Plasmas systeminställningar, har du stött på en listvy. Listvyer låter dig helt enkelt visa data från en lista.
Kirigami.CardsListView {
id: layout
model: kountdownModel
delegate: kountdownDelegate
}
Det verkar kryptiskt, men oroa dig inte. Låt oss börja uppifrån.
Det första du märker är att vi använder Kirigami.CardsListView
. Det är en listvy som låter oss enkelt 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
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 }
}
En modell definierar sättet som en datapost är strukturerad. Genom att titta på vårt listelement ovan kan vi se hur element i kountdownModel är strukturerade: de innehåller ett namn, en beskrivning och ett datum. De två första är bara strängar, och den tredje är ett tal som vi använder som platsmarkering.
Anmärkning
Since QML is built on top of JavaScript, many of this language's features are available for use in QML files. However, JavaScript variables have to be prefixed withproperty
in QML.Modeller är också användbara på det sätt de kan ändras genom användning av flera metoder. Några viktiga är:
- ListModelName.append(jsobject ditt_objekt) lägger till ett Javascript-objekt som du tillhandahåller 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 Javascript-objekt med korrekta egenskaper och motsvarande datatyper.
- ListModelName.get(int index) returnerar JSObject vid indexplatsen du tillhandahåller.
- ListModelName.remove(int index, int count) tar bort JSObject på den tillhandahållna indexplatsen, och så många efter den indexplatsen som du vill (1 inkluderar bara JSObject på tillhandahållet index)
- ListModelName.set(int index, jsobject yourobject) ändrar objektet på tillhandahållen indexplats med värdet som tillhandahålls i yourobject. Samma regel som med
.append
.
Delegera
Delegaten hanterar hur data i ListModel visas i listvyn. CardsListView element är konstruerade med delegater av korttyp i åtanke, och vi har verkligen använd ett Kirigami.AbstractCard
element som vår delegat i utdraget ovan.
Delegater får automatiskt egenskaperna i listelementen som vi har angivit i vår modell. Vi kan därför bara referera till egenskaperna name
, description
och date
för våra listelement som om de var konventionella variabler inne i vår delegat.
Bygga vårt delegatkort
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 < 100000) ? date : i18n("%1 days", Math.round((date-Date.now())/86400000))
}
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
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 elemented GridLayout
. Implicita bredder och höjder är egenskaper som ställs in som en sorts förvalda värden, dvs. om det inte finns någon bredd och höjd inställt för komponenterna. Vi har därför ställt in implicitWidth
och implicitHeight
i vår Kirigami.AbstractCard
till det av vår GridLayout
under, för att säkerställa att vår GridLayout
inte flyter ut utanför kortet.
Layouter
GridLayout
är inne i komponenten Item
vi tillhandahåller för egenskapen contentItem
. Det är objektet som innehåller det vi kommer att visa 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 kolumnRowLayout
placerar ut komponenterna horisontellt, i en enda radGridLayout
placerar ut komponenterna i ett rutnät med en sammansättning du väljer
Allt vi behöver göra med ColumnLayout and RowLayout är att skriva våra komponenter inne i komponenten Layout. Som du kan se, bestämde vi oss för en rutnätslayout, 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år anchor
. 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 Visual Design Group (VDG) has a lot more information about different units defined within Plasma and Kirigami on the Human Interface Guidelines site.Vi har också använt ett villkor här för att variera antal kolumner i vårt rutnät beroende på skärmen vi använder. Om vi använder en bred skärm (dvs. en datorskärm eller en telefon med liggande format) 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.
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änderdate
iListElement
som första nivåns rubrik. - Mitten,
ColumnLayout
: har enKirigami.Heading
som visar aktivitetsnamnet, enKirigami.Separator
som tillhandahåller den horisontella linjen, och enControls.Label
som visar en uppgifts valfria beskrivning. De senare två komponenterna har egenskapenvisible
som kontrollerar om beskrivningen är tom eller inte och visar komponenten beroende på resultatet avdescription.length > 0
. - Just det,
Controls.Button
: en knapp som gör något ... snart.
Vårt program så långt
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.