Основы использования Silica
Модуль Silica предоставляет основные компоненты для построения пользовательского интерфейса приложений ОС Аврора.
Сюда входят компоненты пользовательского интерфейса, основанные на QtQuick, а также средства для стилизации приложений ОС Аврора и управления их поведением. Модуль Silica не только облегчает построение интерфейсов приложений, но и обеспечивает единство стиля оформления с другими приложениями ОС Аврора.
Разработка приложений для ОС Аврора
В основе приложений для ОС Аврора лежит сочетание языков QML и C++: пользовательский интерфейс создаётся с помощью компонентов QML из модулей Silica и QtQuick (и других сторонних модулей), а запуск осуществляется приложением C++ путём вызова основного QML файла в классе QQuickView.
Приложения для ОС Аврора создаются с помощью Аврора SDK. Пример создания проекта приложения для ОС Аврора приведён в данной статье. В этом проекте автоматически создаётся QML-файл с пользовательским интерфейсом и приложение C++ для его запуска.
В QML-файле описывается компоновка пользовательского интерфейса приложения. Рассмотрим возможности модуля Silica путём последовательной доработки сгенерированного пользовательского интерфейса.
Простой пользовательский интерфейс приложения для ОС Аврора
Ниже приведён пример простого приложения ОС Аврора, которое отображает строку текста в центре экрана:
import QtQuick 2.2
import Sailfish.Silica 1.0
ApplicationWindow {
initialPage: Component {
Page {
Label {
text: "Hello world!"
anchors.centerIn: parent
}
}
}
}
Отметим три основные момента в этом пользовательском интерфейсе:
- Сначала выполняется импорт модулей QtQuick и
Sailfish.Silica
для последующего использования соответствующих типов QML; - Для создания главного компонента используется тип ApplicationWindow из модуля Silica;
- Для отображения содержимого в качестве начального экрана задается элемент Page (из модуля Silica), в центре которого расположена текстовая метка Label (из модуля Silica).
С помощью типа ApplicationWindow реализуется компонент верхнего уровня приложения ОС Аврора. По сути, это окно, заключающее в себе пользовательский интерфейс приложения. Каждое окно содержит стек страниц, который отображает текущий экран или, другими словами, страницуприложения. С помощью свойства initialPage в контейнере ApplicationWindow задаётся первоначальная страница приложения. В примере выше при запуске приложения будет показана одиночная страница Page текстовой меткой Label в центре экрана. В качестве значения свойства initialPage можно задать URL файла QML, экземпляр страницы Page или компонент Component с верхнеуровневой страницей Page (как в примере выше).
Теперь, имея простое приложение, можно последовательно дорабатывать пользовательский интерфейс с помощью некоторых QML-типов модуля Silica.
Оформление простого пользовательского интерфейса для ОС Аврора
На основе предыдущего примера можно создать приложение, которое отображает ползунок и кнопку. При нажатии на кнопку текущее значение ползунка добавляется в список:
import QtQuick 2.2
import Sailfish.Silica 1.0
ApplicationWindow {
initialPage: Component {
Page {
Column {
width: parent.width
// Интерактивный ползунок с шагом в диапазоне значений от 0 до 100.
Slider {
id: slider
label: "Простой ползунок"
width: parent.width
minimumValue: 0; maximumValue: 100; stepSize: 1
valueText: value
}
Button {
text: "Сохранить"
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
listModel.append({"sliderValue": "Значение: " + slider.value})
}
}
Repeater {
model: ListModel { id: listModel }
Label { text: model.sliderValue }
}
}
}
}
}
Так же как и в предыдущем примере, приложение и его первоначальная страница с содержимым создаются с помощью QML-типов ApplicationWindow и Page. Коме того, в приложении используются:
- Тип Slider (из модуля Silica) для отображения горизонтального ползунка.
- Тип Button (из модуля Silica) для отображения интерактивной кнопки.
- Тип Label (из модуля Silica) для отображения текста.
- Типы Column, ListModel и Repeater (из стандартного модуля QtQuick) для компоновки элементов на экране и наполнения списка значениями, заданными с помощью ползунка. Тип Repeater создаёт экземпляр своего дочернего элемента верхнего уровня (в данном примере — текстовой метки Label) для каждого элемента своей модели.
Приложение для ОС Аврора полностью работоспособно, однако в нем отсутствуют некоторые возможности, которые сделают его более презентабельным и удобным для использования. Например:
- Значения ползунка можно было бы удалять из списка.
- Элементы списка расположены непосредственно у левой границы экрана без отступа.
- Страница не содержит заголовка.
- Страницу нельзя прокручивать после наполнения списка достаточно большим количеством записей.
Все это можно исправить с помощью других типов модуля Silica, а также с помощью объекта Theme.
Добавление элемента ListItem в список
Тип ListItem модуля Silica реализует стандартный компонент для элементов списка с возможностью добавления контекстного меню. Контекстное меню предоставляет набор команд, которые пользователь может вызвать применительно к конкретному элементу списка.
В примере ниже использование типа ListItem превращает каждый элемент списка в интерактивный элемент с набором соответствующих действий. Достигается это путём замены дочернего элемента типа Repeater на ListItem и переносом туда текстовой метки Label. Затем с помощью свойства menu в элементе ListItem создается контекстное меню ContextMenu, состоящее из одной команды, описанной в контейнере MenuItem. Вызов этой команды удаляет соответствующий элемент из модели:
Repeater {
model: ListModel { id: listModel }
ListItem {
width: parent.width
Label {
text: model.sliderValue
anchors.verticalCenter: parent.verticalCenter
}
menu: ContextMenu {
MenuItem {
text: "Удалить"
onClicked: {
listModel.remove(model.index)
}
}
}
}
}
Теперь, когда пользователь нажимает и удерживает элемент списка, появляется меню, которое позволяет удалить данный элемент из списка.
Пожалуй, было бы гораздо удобнее, если бы при удалении элемента из списка пользователь подтверждал это действие и, при необходимости, мог бы отменить его. В ОС Аврора для этого существует специальная концепция отмены разрушающего действия (remorse action), позволяющая пользователю отменить разрушающее действие перед его непосредственным исполнением. которая реализуется с помощью типов RemorseItem и RemorsePopup: вместо незамедлительного выполнения действия пользователю предоставляется возможность в течение некоторого времени отменить данное действие.
Для отмены разрушающего действия в объектах ListItem нет необходимости использовать типы RemorseItem или RemorsePopup напрямую. Вместо этого тип ListItem предоставляет соответствующий метод remorseAction(), который сначала покажет таймер обратного отсчёта, а затем по истечении времени выполнит заданное действие. Следует изменить обработчик onClicked контекстного меню так, чтобы в нём вызывался метод remorseAction() . В данный метод, в свою очередь, передаётся функция, вызывающая метод ListModel remove(), когда таймер обратного отсчёта достигнет нуля:
Repeater {
model: ListModel { id: listModel }
ListItem {
id: listEntry // идентификатор для обращения к элементу в обработчике onClicked()
width: parent.width
Label {
text: model.sliderValue
anchors.verticalCenter: parent.verticalCenter
}
menu: ContextMenu {
MenuItem {
text: "Удалить"
onClicked: {
listEntry.remorseAction("Deleting", function() { listModel.remove(model.index) })
}
}
}
}
}
Остались небольшие проблемы с текстовой меткой: в соответствии с соглашением, принятым для приложений ОС Аврора, все интерактивные элементы (т.е. элементы, реагирующие на касания, такие как Button или элементы списка, как в примере) должны менять соответствующим образом свой цвет при нажатии. Кроме того, необходимо добавить интервал между элементами списка, отступ от края страницы, а также отступы сверху и снизу для кнопки Сохранить.
Обе эти проблемы можно решить стандартным для приложений ОС Аврора способом с помощью объекта Theme.
Стилизация интерфейса пользователя с помощью объекта Theme
Объект Theme предоставляет стандартные стилевые параметры для компонентов пользовательского интерфейса приложений ОС Аврора. С его помощью можно задавать цвета, гарнитуры шрифтов, размеры, отступы и прочие характеристики пользовательского интерфейса в стиле ОС Аврора.
Например, свойство Theme.horizontalPageMargin определяет стандартное расстояние
между краями страницы и её содержимым. В примере можно использовать его для задания отступа от левой границы у элементов
списка. Кроме того, свойства Theme.primaryColor и
Theme.highlightColor определяют цвета элементов в обычном состоянии и при их подсветке
в соответствии с текущей атмосферой ОС Аврора. Поэтому, с помощью свойства
highlighted элемента списка (возвращает true
, когда элемент списка
подсвечивается при нажатии) можно задать условие для раскрашивания текстовой метки — свойство
color будет принимать соответствующий цвет:
ListItem {
id: listEntry
width: parent.width
Label {
color: listEntry.highlighted ? Theme.highlightColor : Theme.primaryColor // Подходящее окрашивание текста
text: model.sliderValue
x: Theme.horizontalPageMargin
anchors.verticalCenter: parent.verticalCenter
}
menu: ContextMenu {
MenuItem {
text: "Удалить"
onClicked: {
listEntry.remorseAction("Удаление", function() { listModel.remove(model.index) })
}
}
}
}
Для добавления отступа между ползунком, кнопкой и списком, нужно установить свойство spacing
столбца в значение
Theme.paddingLarge — стандартное расстояние между элементами на странице. Поскольку этот
отступ не должен применяться к элементам списка, можно разместить элемент
Repeater и его дочерние элементы в новом столбце
Column, в котором по умолчанию используется нулевой
отступ:
Page {
// Основной столбец
Column {
width: parent.width
spacing: Theme.paddingLarge // Добавляется интервал между элементами в столбце
// Slider { ... }
// Button { ... }
// Вложенный столбец, содержащий элемент Repeater и элементы списка
Column {
width: parent.width
// Repeater { ... }
}
}
}
Дальнейшие улучшения
Как правило, в каждой странице приложения, созданного с помощью модуля Silica, сверху должен отображаться заголовок. Также должна обеспечиваться прокрутка, если в списке много элементов.
С помощью типа Silica PageHeader можно добавить заголовок над основным столбцом, а также включить прокрутку для списка путём помещения столбца Column в контейнер SilicaFlickable. В дополнение к этому можно добавить вертикальный индикатор прокрутки VerticalScrollDecorator как дочерний элемент контейнера SilicaFlickable. Этот индикатор представляет собой вертикальную полоску, которая отображается справа при прокручивании содержимого и обозначает его текущее положение и общую площадь.
Page {
PageHeader {
id: header
title: "Пример Аврора"
}
SilicaFlickable {
anchors {
top: header.bottom
bottom: parent.bottom
left: parent.left
right: parent.right
}
contentHeight: mainColumn.height
// Основной столбец
Column {
id: mainColumn
// ... содержимое основного столбца
}
VerticalScrollDecorator {}
}
}
Также было бы полезно иметь возможность полной очистки списка. Сделать это можно с помощью вытягиваемых меню: такие меню по умолчанию скрыты и показываются при прокручивании родительского элемента. Можно добавить элемент PullDownMenu (вытягиваемое меню, отображаемое в верхней части страницы) в контейнер SilicaFlickable:
SilicaFlickable {
PullDownMenu {
MenuItem {
text: "Очистить"
onClicked: listModel.clear()
}
}
// ... Содержимое элемента с прокруткой
}
Примечание. Было бы удобнее, если бы список очищался не сразу, а с кратковременной возможностью отмены действия, как это было сделано ранее с помощью метода remorseAction(). В данном случае, такую функциональность можно реализовать с помощью объекта RemorsePopup путём вызова его метода execute().
Замена списка в столбце на SilicaListView
На текущий момент данные отображаются с помощью комбинации типов SilicaFlickable, Column и Repeater. При использовании типа Column следует помнить, что все его дочерние элементы создаются всегда, даже если содержимое столбца выходит за пределы видимой области экрана. Этого будет вполне достаточно, если количество элементов в списке относительно невелико. Если же список состоит из сотен или тысяч элементов, или если делегат включает множество деталей для отрисовки, то такой подход приведет к снижению производительности приложения.
В последнем случае будет предпочтительнее использовать тип SilicaListView (основан на типе
ListView из модуля
QtQuick), который создаёт и отрисовывает делегаты только в видимой
области экрана (а также делегаты за пределами экрана в количестве, указанном в параметре
cacheBuffer). Для этого нужно заменить тип
SilicaFlickable на SilicaListView, а также переместить свойства model
и
delegate
из контейнера Repeater в контейнер списка:
Page {
SilicaListView {
anchors.fill: parent
model: ListModel { id: listModel }
delegate: ListItem {
// ... Содержимое элемента
}
// Вложенный столбец, содержащий элемент Repeater и элементы списка, больше не требуется
// и может быть удалён
VerticalScrollDecorator {}
PullDownMenu {
MenuItem {
text: "Очистить"
onClicked: listModel.clear()
}
}
}
}
Для большего удобства заголовок страницы PageHeader и основной столбец Column (с ползунком Slider и кнопкой Button можно вынести в область заголовка вида с прокруткой (унаследованное свойство header), чтобы эти элементы прокручивались вместе с отрисованными делегатами. Сделать это можно путём группировки этих элементов в новый контейнер типа Column:
SilicaListView {
header: Column {
width: parent.width
height: header.height + mainColumn.height + Theme.paddingLarge // добавляет пробел между кнопкой и первым элементом списка
PageHeader {
id: header
title: "Пример Аврора"
}
// Основной столбец
Column {
id: mainColumn
// ... содержимое основного столбца
}
}
// ... остальной код SilicaListView
}
Итого
Таким образом, для создания простого пользовательского интерфейса приложения ОС Аврора следует выполнить:
- Создать корневой компонент ApplicationWindow и назначить ему первоначальную страницу initialPage.
- Добавить такие компоненты, как Label, Button, Slider и ListItem из модуля Silica для начала отображения данных и получения ввода пользователя.
- Использовать тип Theme для стилизации пользовательского интерфейса и применения стандартных цветов, размеров и отступов.
- Доработать пользовательский интерфейс путём добавления вытягиваемых меню (PullDownMenu и PushUpMenu) и отсроченных разрушающих действий (либо с помощью встроенных методов типа ListItem, либо с помощью отдельных специализированных объектов RemorseItem и RemorsePopup).
Ниже приведён полный пример кода:
import QtQuick 2.2
import Sailfish.Silica 1.0
ApplicationWindow {
initialPage: Component {
Page {
SilicaListView {
anchors.fill: parent
header: Column {
width: parent.width
height: header.height + mainColumn.height + Theme.paddingLarge
PageHeader {
id: header
title: "Пример Аврора"
}
Column {
id: mainColumn
width: parent.width
spacing: Theme.paddingLarge
Slider {
id: slider
label: "Простой ползунок"
width: parent.width
minimumValue: 0; maximumValue: 100; stepSize: 1
valueText: value
}
Button {
text: "Сохранить"
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
listModel.append({"sliderValue": "Значение: " + slider.value})
}
}
}
}
model: ListModel { id: listModel }
delegate: ListItem {
id: listEntry
width: parent.width
Label {
color: listEntry.highlighted ? Theme.highlightColor : Theme.primaryColor
text: model.sliderValue
x: Theme.horizontalPageMargin
anchors.verticalCenter: parent.verticalCenter
}
menu: ContextMenu {
MenuItem {
text: "Удалить"
onClicked: {
listEntry.remorseAction("Удаление", function() {
listModel.remove(model.index)
})
}
}
}
}
PullDownMenu {
MenuItem {
text: "Очистить"
onClicked: listModel.clear()
}
}
VerticalScrollDecorator {}
}
}
}
}
Другие полезные типы Silica
В дополнение к уже упомянутым типам Silica можно привести ещё несколько полезных типов:
Типы | Краткое описание |
---|---|
TextField и TextArea | Типы ввода текста |
TextSwitch, ProgressBar и ComboBox | Основные типы пользовательского интерфейса |
SilicaGridView | Представление в виде сетки, основанное на типе GridView модуля QtQuick |
SectionHeader и Separator | Визуальное разделение компонентов на экране |
Dialog | Специализированная страница с кнопками Принять и Отменить в заголовке для пользовательских действий принятия и отмены |
См. также полный список типов в разделе Справочная документация Silica.