Skip to main content
Ir para o conteúdo

Layouts, ListViews e Cards

Descobrindo as diferentes maneiras de colocar coisas em uma página

Dispondo seu conteúdo

Agora que entendemos como as páginas funcionam, é hora de adicionar elementos a elas. Abordaremos uma série de componentes e elementos de layout importantes que serão úteis ao projetar nosso aplicativo.

Ao final desta seção, você terá um aplicativo com uma aparência bacana.

ListViews

Se você já usou o Discover, o NeoChat ou as Configurações do Sistema do Plasma, você já deve ter se deparado com uma ListView. Simplificando, ela permite que você exiba dados em uma lista.

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

Parece enigmático, mas não se preocupe. Vamos começar do começo.

Adicionamos este componente dentro do nosso Kirigami.ScrollablePage do último tutorial.

Estamos usando Kirigami.CardsListView, que é uma ListView que nos permite exibir facilmente cartões em uma lista. No entanto, ListViews são feitas para mostrar dados retirados de um modelo - para se preencherem automaticamente com um conjunto de dados para o qual apontamos. É aí que entra a propriedade model: neste exemplo, ela aponta para kountdownModel.

Modelo

Kirigami.ApplicationWindow {
    // ...
    ListModel {
        id: kountdownModel
        // Cada ListElement é um elemento da lista, contendo informações
        ListElement {
            name: "Dog birthday!!"
            description: "Big doggo birthday blowout."
            date: 100
        }
    }
    // ...
}

Adicionamos nosso kountdownModel dentro do Kirigami.ApplicationWindow do último tutorial.

Um modelo define a maneira como uma entrada de dados é estruturada. Nosso kountdownModel consistirá em apenas um elemento por enquanto. Observando nosso ListElement acima, podemos ver como os dados do nosso kountdownModel são estruturados: ele contém um nome, uma descrição e uma data. Isso não é imutável, e você pode ter diferentes tipos de dados em seu modelo. Os dois primeiros são apenas strings, e o terceiro é um número que estamos usando como espaço reservado.

Os modelos também são úteis na forma como podem ser modificados através do uso de vários métodos. Alguns importantes são:

Delegados

Enquanto nosso kountdownModel contém os dados que serão exibidos, nosso kountdownDelegate controlará como os dados serão exibidos na ListView. Para isso, usamos uma Kirigami.CardsListView projetada para exibir delegados do tipo cartão, e esses delegados serão representados visualmente por meio de um Kirigami.AbstractCard.

Os delegados recebem automaticamente as propriedades das instâncias do ListElement que especificamos em nosso modelo. Portanto, podemos simplesmente nos referir às suas propriedades nome, descrição e data como se fossem variáveis ​​convencionais em nosso delegado.

Construindo o cartão delegado

O Componente que representará nosso delegado pode ser adicionado dentro do nosso Kirigami.ApplicationWindow. Em seguida, verificaremos o que cada parte do nosso componente delegado faz.

Kirigami.ApplicationWindow {
    // ...
    Component {
        id: kountdownDelegate
        Kirigami.AbstractCard {
            contentItem: Item {
                // implicitWidth/Height define a largura/altura natural de um item se nenhuma
                // largura ou altura for especificada. A configuração abaixo define o tamanho
                // preferencial de um componente com base em seu conteúdo
                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: a ser feito... em breve!
                    }
                }
            }
        }
    }
    // ...
}

implicitWidth e implicitHeight

A primeira parte que veremos é como gerenciar a largura e a altura do nosso componente:

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

Observando nosso Kirigami.AbstractCard, as primeiras propriedades que definimos são implicitWidth e implicitHeight. Definimos essas propriedades como delegateLayout.implicitWidth e delegateLayout.implicHeight, ou seja, o implicitWidth e implicitHeight do elemento GridLayout.

Larguras e alturas implícitas são propriedades disponíveis em qualquer Item que funcionam como dicas e são definidas como padrão, ou como alternativa, caso não haja largura ou altura explícitas definidas para esses componentes. Esses valores são, por padrão, 0x0, portanto, é muito importante que você os defina nos componentes brutos do Item, conforme feito acima.

Aqui, definimos implicitWidth e implicitHeight do nosso Kirigami.AbstractCard como o do GridLayout abaixo para garantir que ele não transborde do cartão. Dessa forma, o cartão ocupa o espaço necessário para o seu conteúdo.

Layouts

O GridLayout está dentro do componente Item que fornecemos para a propriedade contentItem. Este é o Item que contém o que será exibido no seu cartão.

Também precisamos escolher um layout para nossos componentes, para que eles não fiquem empilhados uns sobre os outros. Há três tipos principais que podemos escolher:

  • ColumnLayout dispõe seus componentes verticalmente, em uma única coluna
  • RowLayout dispõe seus componentes horizontalmente, em uma única linha
  • GridLayout dispõe seus componentes em uma grade com uma composição de sua escolha

Com ColumnLayout e RowLayout, tudo o que precisamos fazer é escrever nossos componentes dentro do componente Layout. Como você pode ver, optamos por um GridLayout, o que requer um pouco mais de trabalho 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
    // ...
}

A primeira coisa que você vê são nossas âncoras. O sistema de ancoragem do QtQuick fornece uma maneira útil de garantir que seus componentes estejam posicionados em determinadas partes de um componente pai. Ancoramos nosso GridLayout à esquerda, superior e direita do cartão pai, garantindo que nosso conteúdo se estenda por todo o cartão.

Em seguida, especificamos o espaçamento entre as linhas e colunas em nossa grade, para que nossos componentes não fiquem amontoados. O Kirigami fornece uma série de unidades predefinidas úteis para esse propósito:

Unidades do KirigamiPixels
smallSpacing4px
largeSpacing8px
gridUnit18px

Como você deve se lembrar, root é o id do nosso Kirigami.ApplicationWindow. Ele fornece a propriedade wideScreen, usada para determinar se a tela atual do dispositivo é widescreen (ou seja, um monitor de computador ou um telefone em modo paisagem). Usamos um condicional ternário aqui para variar o número de colunas em nossa grade dependendo da tela que estamos usando: se for widescreen, a grade terá 4 colunas, caso contrário, terá 2.

Componentes internos

Poderíamos criar apenas três rótulos dentro do nosso componente delegado e encerrar o dia, mas isso não ficaria muito bom. Usaremos alguns componentes mais convenientes:

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")
    }
}
Como o cartão personalizado se parece

Como o cartão personalizado se parece

  • À esquerda, Kirigami.Heading: usa a data do ListElement como um título de nível 1.
  • No meio, ColumnLayout: possui um Kirigami.Heading que exibe o nome da tarefa; um Kirigami.Separator, que fornece a linha horizontal; e um Controls.Label, que exibe a descrição opcional da tarefa. Os dois últimos componentes têm uma propriedade visible, que verifica se a descrição está vazia ou não e exibe os componentes dependendo do resultado de description.length > 0.
  • À direita, Controls.Button: um botão que fará algo... em breve!

Nosso aplicativo até agora

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

Captura de tela da aparência do aplicativo após concluir esta lição

Então aqui está o nosso cartão básico!

Com essas etapas, estabelecemos a base para adicionar todas as funcionalidades ao nosso aplicativo.