Документация
ОС Аврора 5.1.5

Основы использования 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
}

Итого

Таким образом, для создания простого пользовательского интерфейса приложения ОС Аврора следует выполнить:

  1. Создать корневой компонент ApplicationWindow и назначить ему первоначальную страницу initialPage.
  2. Добавить такие компоненты, как Label, Button, Slider и ListItem из модуля Silica для начала отображения данных и получения ввода пользователя.
  3. Использовать тип Theme для стилизации пользовательского интерфейса и применения стандартных цветов, размеров и отступов.
  4. Доработать пользовательский интерфейс путём добавления вытягиваемых меню (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.

Мы используем cookies для персонализации сайта и его более удобного использования. Вы можете запретить cookies в настройках браузера.

Пожалуйста ознакомьтесь с политикой использования cookies.