Disposicions (Layout), vistes de llista (ListView) i targetes (Card)

Descobrint les diferents formes de col·locar les coses en una pàgina

Dissenyar el contingut

Ara que entenem com funcionen les pàgines, és hora d’afegir-hi coses. Repassarem una sèrie de components i elements de disposició importants que seran útils en dissenyar la nostra aplicació.

No us espanteu pels grans trossos de codi! Repassarem tot el que no hem cobert abans i, al final d’aquesta secció, tindreu una aplicació d’aspecte impecable.

Vistes de llista (ListView)

Si heu emprat alguna vegada el Discover, el NeoChat o l’Arranjament del sistema del Plasma, us haureu trobat amb una vista de llista. En poques paraules, les vistes de llista permeten mostrar les dades en una llista.

Kirigami.CardsListView {
    id: layout
    model: kountdownModel
    delegate: kountdownDelegate
}

Això sembla críptic, però no us preocupeu. Comencem des de dalt.

El primer que notareu és que estem emprant la Kirigami.CardsListView. És una vista de llista que ens permet mostrar targetes en una llista amb facilitat. No obstant això, les vistes de llista estan fetes per a mostrar les dades preses des d’un model -per a emplenar-se automàticament a partir d’un conjunt de dades a les quals apuntem-. Aquí és on entra la propietat model: en aquest exemple, apunta a kountdownModel.

Model

ListModel {
    id: kountdownModel
    // Cada ListElement és un element en la llista que conté informació
    ListElement { name: "Dog birthday!!"; description: "Big doggo birthday blowout."; date: 100 }
}

Un model defineix la forma en què s’estructura una entrada de dades. En mirar el nostre ListElement anterior, veurem com s’estructuren els elements d’un kountdownModel: contenen un nom, una descripció i una data. Els dos primers només són cadenes i el tercer és un número que utilitzem com a marcador de posició.

Els models també són útils perquè es poden modificar mitjançant l’ús de diversos mètodes. Alguns importants són:

  • ListModelName.append(objecte_js objecte_vostre) afegeix un objecte de JavaScript que proporcioneu al ListModel i el col·loca després de l’últim element del model. Perquè això succeeixi correctament, haureu de proporcionar un objecte de JavaScript amb les propietats correctes i els tipus de dades corresponents.
  • ListModelName.get(int index) retorna el JSObject en la ubicació de l’índex que heu proporcionat.
  • ListModelName.remove(int index, int count) elimina el JSObject en la ubicació proporcionada de l’índex, i tantes com vulgueu després d’aquesta ubicació de l’índex (1 només inclou el JSObject a l’índex proporcionat).
  • ListModelName.set(int index, objecte_js objecte_vostre) canvia l’element en la ubicació proporcionada de l’índex amb els valors proporcionats a objecte_vostre. Les mateixes regles que amb .append.

Delegat

El delegat gestiona com es mostraran les dades de la vostra ListModel a la vista de llista. Els elements CardsListView estan dissenyats tenint en compte els delegats de tipus targeta i, de fet, en el fragment anterior hem utilitzat un element Kirigami.AbstractCard com el nostre delegat.

Els delegats reben automàticament les propietats dels ListElements que hem especificat en el nostre model. Per tant, només podem fer referència a les propietats name, description i date dels nostres ListElements com si fossin una variable convencional dins del nostre delegat.

Construir la nostra targeta de delegat

Component {
    id: kountdownDelegate
    Kirigami.AbstractCard {
        contentItem: Item {
            // implicitWidth/Height defineix l'amplada/alçada natural d'un element si no se
            // n'especifica cap. La configuració següent defineix la mida preferida d'un component
            // en funció del seu contingut.
            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: s'ha de fer... aviat!
                }
            }
        }
    }
}

implicitWidth i implicitHeight

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

Mirant la nostra Kirigami.AbstractCard, les primeres propietats que establim són implicitWidth i implicitHeight. Les hem establert a la delegateLayout.implicitWidth i delegateLayout.implicitHeight, és a dir, les implicitWidth i implicitHeight de l’element GridLayout. Les amplades i alçades implícites són propietats que s’estableixen com una mena de valor predeterminat, és a dir, si no hi ha una amplada o alçada explícita establerta per a aquests components. Per tant, haurem establert la implicitWidth i implicitHeight de la nostra Kirigami.AbstractCard a la de la GridLayout següent per a assegurar-nos que la GridLayout no se surti de la targeta.

Disposicions

La GridLayout està dins del component Item que hem proporcionat per a la propietat contentItem. Aquest és l’element que conté el que es mostrarà a la vostra targeta.

També haurem de triar una disposició per als nostres components, de manera que no s’apilin un damunt de l’altre. Hi ha tres tipus principals entre les quals podem triar:

  • ColumnLayout distribueix els components verticalment, en una sola columna
  • RowLayout distribueix els components horitzontalment, en una sola fila
  • GridLayout distribueix els components en una quadrícula amb una composició de la vostra elecció

Amb ColumnLayout i RowLayout, tot el que hem de fer és escriure els nostres components dins del component Layout. Com podeu veure, hem optat per una disposició de quadrícula, la qual implica una mica més de treball manual.

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

El primer que veieu és la nostra anchor. El sistema d’ancoratge de QtQuick proporciona una forma útil d’assegurar-vos que els components estiguin col·locats en certes parts d’un component pare. Hem ancorat la nostra GridLayout a l’esquerra, a dalt i a la dreta de la targeta principal, assegurant que el nostre contingut s’estengui per tota la targeta.

A continuació, especificarem l’espai entre les files i les columnes dins la nostra quadrícula, de manera que els nostres components no s’amunteguin. El Kirigami proporciona una sèrie d’útils unitats predefinides per a utilitzar amb aquest propòsit:

Unitat de KirigamiPíxels
smallSpacing4px
largeSpacing8px
gridUnit18px

Aquí també hem utilitzat un condicional per a variar el nombre de columnes a la nostra quadrícula depenent de la pantalla que estiguem emprant. Si emprem una pantalla ampla (és a dir, un monitor d’ordinador o un telèfon en apaïsat), la quadrícula tindrà 4 columnes, en cas contrari en tindrà 2.

Components interiors

Podríem crear tres etiquetes dins del nostre component delegat i cridar-les un dia. Però això no es veuria particularment bonic.

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

  • Esquerra, Kirigami.Heading: utilitza la date d’un ListElement com una capçalera de nivell 1.
  • Enmig, ColumnLayout: té una Kirigami.Heading que mostra el nom de la tasca. Un Kirigami.Separator, el qual proporciona la línia en horitzontal i un Controls.Label, que mostra una descripció opcional de la tasca. Els dos últims components tenen una propietat visible, la qual comprova si la descripció està buida o no, i mostra els components segons el resultat de description.length > 0.
  • Dreta, Controls.Button: un botó que farà alguna cosa… aviat!

La nostra aplicació fins ara

Així que aquí està la nostra targeta bàsica!

Amb aquests passos, hem establert les bases bàsiques per a afegir tota la funcionalitat a la nostra aplicació.