Эта статья была рецензирована Марком Таулером . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!
Списки и Сетка являются одним из основных строительных блоков любого мобильного приложения.
В этой статье я собираюсь представить дизайн SilicaListView
и SilicaGridView
, реализацию Silica этих общих компонентов. Мы увидим несколько примеров того, как отображать типы данных, обрабатывать клики и многое другое, делая код максимально простым.
Дизайн МВД
Интерфейсы Sailfish OS основаны на QML , декларативном языке, предоставляемом QT Framework . Чтобы предоставить разработчику или разработчику контроль над различными аспектами приложения, QT использует шаблон проектирования Model-View-Delegate для модульной визуализации данных.
Модель содержит данные и их структуру, а представление — это контейнер, который отображает данные. В нашем случае представлением будет список или сетка. Наконец, делегат диктует, как отдельный элемент данных будет отображаться в представлении.
SilicaListView
Давайте начнем с простого примера:
import QtQuick 2.0 import Sailfish.Silica 1.0 Page { id: page SilicaListView { width: parent.width; height: parent.height model: ListModel { ListElement { name: "Paul"; telephone: "342342341" } ListElement { name: "Laura"; telephone: "343241" } ListElement { name: "Luca"; telephone: "6454341" } ListElement { name: "Daniel"; telephone: "23431231" } ListElement { name: "Seb"; telephone: "666342342341" } ListElement { name: "Carl"; telephone: "55342342341" } } delegate: Item { width: parent.width height: Theme.itemSizeMedium Label { text: name font.pixelSize: Theme.fontSizeMedium anchors { left: parent.left right: parent.right margins: Theme.paddingLarge } } } } }
Помимо компонентов страницы ( SilicaListView
с этой статьей для ознакомления с компонентами Silica), мы объявили SilicaListView
с жестко закодированной моделью. Список будет выглядеть так:
Каждый ListElement
— это объект с двумя свойствами — именем и номером телефона.
Делегат — это просто Item
(базовый компонент QML) со свойством width, установленным для заполнения ширины ListView
и значением height, установленным с помощью объекта Theme
Фактический размер вычисляется во время выполнения, адаптируя его к используемому отображению. ,
Делегат содержит Label
с именем контакта. Чтобы показать номер телефона, я могу добавить еще одну метку делегату:
Item { width: parent.width height: Theme.itemSizeMedium anchors { left: parent.left right: parent.right margins: Theme.paddingLarge } Label { id: cName text: name font.pixelSize: Theme.fontSizeMedium anchors { left: parent.left right: parent.right } } Label { text: "Tel: " + telephone font.pixelSize: Theme.fontSizeSmall anchors { left: parent.left + Theme.paddingSmall right: parent.right top: cName.bottom } }
Модель и Делегат могут быть определены встроенными, но по мере того, как модели становятся больше, лучше переместить их в другой файл QML.
Например, вы можете создать файл ContactsModel.qml с таким содержимым:
import QtQuick 2.0 ListModel { ListElement { name: "Paul"; telephone: "342342341"; team: "IT" } ListElement { name: "Laura"; telephone: "343241"; team: "IT"} ListElement { name: "Luca"; telephone: "6454341"; team: "IT" } ListElement { name: "Daniel"; telephone: "23431231"; team: "Sales" } ListElement { name: "Seb"; telephone: "666342342341"; team: "Sales" } ListElement { name: "Carl"; telephone: "55342342341"; team: "Sales" } }
И использовать его в качестве модели списка:
model: ContactsModel {}
Я добавил свойство команды для использования в следующем примере.
List
иногда необходимо разделить на разделы. Сделайте это, используя свойство section
чтобы определить ключ модели, используемый в качестве элемента группировки, и делегат для использования в качестве заголовка раздела.
Определите свойство раздела в SilicaListView
:
section { property: "team" criteria: ViewSection.FullString delegate: SectionHeader { text: section } }
Теперь пришло время обрабатывать события кликов и реагировать на них.
MouseArea { anchors.fill: parent onClicked: { var name = list.model.get(index).name console.log(name); }
Мы определили элемент MouseArea
заполняющий наш делегат. Таким образом, мы можем отловить и обработать событие click и получить элемент clicked, используя свойство list get
и index
.
Каждый список может иметь верхний и нижний колонтитулы, прикрепленные к соответствующему свойству списка. Это полезно, поскольку вы не должны включать SilicaListView
или GridView
в другой элемент Scrollable. Если вам нужно содержимое до или после списка / сетки, используйте эти свойства.
SilicaListView { id:list width: parent.width; height: parent.height model: ContactModel {} header: MyHeader {} footer: Button { width: parent.width anchors.margins: Theme.paddingSmall text: "Load more..." onClicked: console.log("clicked!") } section { property: "team" criteria: ViewSection.FullString delegate: SectionHeader { text: section } } delegate: Item { width: parent.width height: Theme.itemSizeMedium anchors { left: parent.left right: parent.right margins: Theme.paddingLarge } Label { id: cName text: name font.pixelSize: Theme.fontSizeMedium anchors { left: parent.left right: parent.right } } Label { text: "Tel: " + telephone font.pixelSize: Theme.fontSizeSmall anchors { left: parent.left right: parent.right top: cName.bottom } } MouseArea { anchors.fill: parent onClicked: { var name = list.model.get(index).name console.log(name); } } } }
Мы можем объявить объекты встроенными или в отдельном файле. В качестве примера я создал файл MyHeader.qml с этим содержимым и объявил нижний колонтитул встроенным:
import QtQuick 2.0 import Sailfish.Silica 1.0 PageHeader { title: "Numbers" }
модели
Чтобы упростить жизнь разработчика QML, определите набор готовых к использованию моделей, таких как SqliteModel
, XmlListModel
и SparqlModel
. Вы можете определить свои собственные модели, используя C ++ QT API .
Например, мы можем отобразить последние новости Sitepoint, используя RSS-канал сайта. Давайте определим нашу модель, используя предопределенный XmlListModel
:
XmlListModel { id: feedModel source: "http://www.sitepoint.com/feed/" query: "/rss/channel/item" XmlRole { name: "title"; query: "title/string()" } XmlRole { name: "link"; query: "link/string()" } XmlRole { name: "description"; query: "description/string()" } XmlRole { name: "pubDate"; query: "pubDate/string()" } }
Здесь мы определяем источник канала и свойство запроса, которые устанавливают область для модели. Будут использоваться только дочерние <item>
, а три XmlRole
действуют как свойство внутри ListElement
.
Теперь мы можем сделать наше представление списка, используя эту модель, полный пример выглядит следующим образом:
import QtQuick 2.0 import Sailfish.Silica 1.0 import QtQuick.XmlListModel 2.0 Page { id: page SilicaListView { id:list width: parent.width; height: parent.height model: XmlListModel { id: feedModel source: "http://www.sitepoint.com/feed/" query: "/rss/channel/item" XmlRole { name: "title"; query: "title/string()" } XmlRole { name: "link"; query: "link/string()" } XmlRole { name: "description"; query: "description/string()" } XmlRole { name: "pubDate"; query: "pubDate/string()" } } header: MyHeader {} footer: Button { width: parent.width anchors.margins: Theme.paddingSmall text: "Load more..." onClicked: console.log("clicked!") } delegate: Item { width: parent.width height: Theme.itemSizeMedium anchors { left: parent.left right: parent.right margins: Theme.paddingLarge } Label { id: cName text: title font.pixelSize: Theme.fontSizeSmall anchors { left: parent.left right: parent.right } } MouseArea { anchors.fill: parent onClicked: { var name = list.model.get(index).name console.log(title); } } } } }
Нам нужно обратиться к ситуациям, когда у нас нет элементов для отображения, например, когда канал все еще загружается.
Мы можем использовать элемент ViewPlaceholder
для обработки этого, ViewPlaceholder
его видимость к свойству count
представления списка:
ViewPlaceholder { enabled: list.count == 0 text: "Loading..." hintText: "Be patient my friend" }
Модели в Js
Если вам нужно сгенерировать модель точно в срок
, вы можете использовать javascript. Мы получаем и отображаем список чисел от 1 до 100 следующим образом:
import QtQuick 2.0 import Sailfish.Silica 1.0 Page { id: page SilicaListView { id:list width: parent.width; height: parent.height model: ListModel { id: myJSModel } header: MyHeader {} footer: Button { width: parent.width anchors.margins: Theme.paddingSmall text: "Load more..." onClicked: console.log("clicked!") } delegate: Item { width: parent.width height: Theme.itemSizeMedium Label { text: value font.pixelSize: Theme.fontSizeMedium anchors { left: parent.left right: parent.right margins: Theme.paddingLarge } } MouseArea { anchors.fill: parent onClicked: { var value = list.model.get(index).value console.log(value); } } } Component.onCompleted: { for(var i=0;i<=100;i++) { var myElement = { "value" : i } myJSModel.append(element) } } } }
myElement
может быть произвольным объектом javascript, и мы можем добавить столько свойств, сколько необходимо, и использовать их в нашем делегате.
Мы определили модель JavaScript в событии Component.onCompleted
. При этом наш код вызывается, когда связанные компоненты готовы и отображаются.
GridViews
GridView
действует аналогично списку, разделяя большинство свойств.
import QtQuick 2.0 import Sailfish.Silica 1.0 Page { id: page SilicaGridView { id:list width: parent.width; height: parent.height cellWidth: width / 2 cellHeight: width / 2 model: ListModel { id: myJSModel } header: MyHeader {} delegate: Item { width: list.cellWidth height: list.cellHeight Label { text: value font.pixelSize: Theme.fontSizeMedium anchors { left: parent.left right: parent.right margins: Theme.paddingLarge } } MouseArea { anchors.fill: parent onClicked: { var value = list.model.get(index).value console.log(value); } } } Component.onCompleted: { for(var i=0;i<=100;i++) { var element = { "value" : i } myJSModel.append(element) } } } }
Мы должны определить еще два свойства, такие как представление списка, cellWidth
и cellHeight
, которые cellHeight
сами за себя.
Вывод
Списки и таблицы популярны, но их не всегда легко реализовать.
Благодаря QML Sailfish имеет один из самых чистых и удобных API-интерфейсов, касающихся этих двух важнейших компонентов, что позволяет разработчику без особых усилий создать удобный пользовательский интерфейс.
Я хотел бы услышать ваши мысли и комментарии, и если вы уже пробовали какую-либо разработку Sailfish.