Układy, widoki list oraz karty
Układanie twojej treści
Teraz, gdy już rozumiemy jak działają strony, pora na dodanie naszych rzeczy. Przejdziemy przez kilka ważnych składników układów i rzeczy, które będą użyteczne przy tworzeniu naszej aplikacji.
Niech nie przeraża cię duża ilość kodu! Przejdziemy przez wszystko, o czym jeszcze nie mówiliśmy, a na końcu tego rozdziału będziesz miał ładnie wyglądającą aplikację.
ListViews
Jeśli kiedykolwiek używałeś Odkrywcy, NeoChat lub Ustawień Systemowych Plazmy, to na pewno widziałeś widok ListView. Ujmując to prosto, widoki ListViews umożliwiają ci wyświetlanie danych na liście.
Kirigami.CardsListView {
id: layout
model: kountdownModel
delegate: kountdownDelegate
}
Wydaje się to tajemnicze, lecz nie przejmuj się. Zacznijmy od góry.
Pierwszą rzeczą jaką zauważysz, jest to, że używamy Kirigami.CardsListView
. Jest to ListView, który umożliwia nam łatwe wyświetlanie kart na liście. Jednakże, ListViews są stworzone do wyświetlanie danych pobranych z modelu - aby samoczynnie wypełnić się zestawem danych, na który wskażemy. To miejsce, w którym do gry wchodzi właściwość model
: w tym przykładzie wskazuje ona na kountdownModel
.
Model
ListModel {
id: kountdownModel
// Każdy ListElement jest rzeczą na liście, która zawiera pewne dane
ListElement { name: "Dog birthday!!"; description: "Big doggo birthday blowout."; date: 100 }
}
Tryb modalny określa sposób w jaki wpisywanie danych jest ułożone. Patrząc na nasz ListElement powyżej możemy zobaczyć w jaki sposób rzeczy kountdownModel są ułożone: zawierają nazwę, opis oraz datę. Pierwsze dwa są tylko ciągani znaków, a trzeci jest liczbą, która używamy jako pole zastępcze.
Uwaga
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.Modele są także użyteczne w sposób w jaki można je zmieniać poprzez użycie kilku metod. Jedne z ważniejszych to:
- ListModelName.append(jsobject yourobject) dodaje obiekt JavaScript, który dostarczysz do ListModel i umieszcza go za ostatnią rzeczą w modelu. Aby odbyło się to poprawnie, musisz dostarczyć obiekt JavaScript z poprawnymi właściwościami i odpowiednimi rodzajami danych.
- ListModelName.get(int index) zwraca JSObject w miejscu indeksu, który podasz.
- ListModelName.remove(int index, int count) usuwa JSObject w miejscu wskazanym przez index i tyle obiektów po nim ile chcesz (1 oznacza tylko jeden JSObject wskazany przez index)
- ListModelName.set(int index, jsobject twójObiekt) zmienia rzecz pod podanym indeksem na wartości podane w twójObiekt. Te same zasady co z
.append
.
Deleguj
Delegat określa jak dane naszego modelu ListModel będą wyświetlane na widoku ListView. Rzeczy z CardsListView zostały stworzone dla delegatów o rodzaj karty i rzeczywiście użyliśmy rzeczy Kirigami.AbstractCard
w naszym delegacie w wycinku powyżej.
Delegaci samoczynnie otrzymują właściwości ListElements, które określiliśmy w naszym modelu. Stąd możemy odnosić się do właściwości name
, description
oraz date
naszej ListElements tak, jakby były zwykłymi zmiennymi w naszym delegacie.
Budowanie naszej karty delegata
Component {
id: kountdownDelegate
Kirigami.AbstractCard {
contentItem: Item {
// implicitWidth/Height określają naturalną szerokość/wysokość rzeczy, jeśli nie podano
// szerokości lub wysokości. Ustawienie poniżej określa optymalny rozmiar składnika na
// podstawie jego treści
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: do zrobienia... w krótce!
}
}
}
}
}
implicitWidth oraz implicitHeight
Kirigami.AbstractCard {
contentItem: Item {
implicitWidth: delegateLayout.implicitWidth
implicitHeight: delegateLayout.implicitHeight
GridLayout {
id: delegateLayout
...
}
}
}
Patrząc na nasze Kirigami.AbstractCard, pierwszymi właściwościami, które nadamy, to implicitWidth
oraz implicitHeight
. Ustawiliśmy je na delegateLayout.implicitWidth
oraz delegateLayout.implicitHeight
, tj. implicitWidth
oraz implicitHeight
rzeczy GridLayout
. Niejednoznacznie podane szerokości i wysokości są rodzajem domyślnych wartości, tj. nie ma podanej jednoznacznie szerokości i wysokości dla tych składników. Stąd ustawiliśmy implicitWidth
oraz implicitHeight
naszej Kirigami.AbstractCard
na tę z GridLayout
poniżej, aby upewnić się, że GridLayout
nie wyleje naszej karty.
Układy
GridLayout
znajduje się wewnątrz składnika Item
, który podaliśmy we właściwości contentItem
. Jest to rzecz, która zawiera to, co będzie wyświetlane w naszej karcie.
Musimy także wybrać układ dla naszych składników tak, aby nie zgrupowały się jeden na drugim. Istnieją trzy różne rodzaje, z których możemy wybrać:
ColumnLayout
układa twoje składniki w pionie, w pojedynczej kolumnieRowLayout
układa twoje składniki w poziomie, w pojedynczym wierszuGridLayout
układa składnik w siatkę z układem taki jaki sobie wybierzesz
Z ColumnLayout oraz RowLayout jedyne, co musimy zrobić to wpisać nasze składniki do wewnątrz składnika Layout. Jak widzisz, wybraliśmy układ siatki, który wymaga trochę więcej pracy ręcznej.
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
...
}
Pierwszą rzeczą jaką zobaczysz jest nasza anchor
. System kotwiczenia QtQuick dostarcza użytecznych sposobów na zapewnienie, że rzeczy są umieszczone w pewnych częściach rzeczy nadrzędnej. Zakotwiczyliśmy nasz GridLayout
do lewe, do góry i dp prawej naszej karty nadrzędnej, upewniając się, że nasza treść rozciągnie się na całą kartę.
Następnie określamy odstępy pomiędzy wierszami i kolumnami w naszej siatce, tak aby nasze składniki nie zgrupowały się. Kirigami dostarcza kilka przydatnych jednostek do tego celu:
Jednostka Kirigami | Piksele |
---|---|
smallSpacing | 4 piks. |
largeSpacing | 8 piks. |
gridUnit | 18 piks. |
Uwaga
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.Użyliśmy tutaj także warunku, aby zmienić liczbę kolumn na naszej siatce w zależności od ekranu, którego używamy. Jeśli używamy szerokiego ekranu (tj. monitora komputerowego lub telefonu w ustawieniu poziomym) to siatka będzie miała 4 kolumny, w przeciwnym przypadku 2.
Składniki wnętrza
Moglibyśmy stworzyć trzy etykiety wewnątrz naszego składnika delegata i powiedzieć to wszystko. Nie wyglądałoby to jednak szczególnie ładnie.
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")
}
}
- Po lewej,
Kirigami.Heading
: używadate
rzeczyListElement
na 1 poziomie nagłówka. - Środkowe,
ColumnLayout
: maKirigami.Heading
, który wyświetla nazwę zadania;Kirigami.Separator
, który stanowi linię w poziomie; orazControls.Label
, który wyświetla dobrowolny opis zadania. Dwa drugie składniki mają właściwośćvisible
, która sprawdza, czy opis jest pusty, czy nie i wyświetla składniki w zależności od wynikudescription.length > 0
. - Po prawej,
Controls.Button
: przycisk, który będzie coś robić... wkrótce!
Nasza aplikacja w tej chwili
Tak więc jest to nasza podstawowa karta!
Tymi krokami, stworzyliśmy fundament do dodawania całej funkcjonalności do naszej aplikacji.