Распространенные ошибки при разработке приложений Sailfish OS

Отсутствие удобных обложек

Понятие активных обложек приложений и  действий, которые можно выполнить с этими обложками, является одной из основных возможностей многозадачности Sailfish OS. При разработке приложений для Sailfish OS эта особенность кажется несущественной, учитывая, что на Android-, iOS- и Meego-приложениях она не предусмотрена. Тем не менее, это удобный способ предоставления информации о статусе работы приложения, а также возможность выполнения базовых действий с минимизированными приложениями на домашнем экране. Активная обложка должна предоставлять достаточно сведений о содержимом приложения и о любых текущих задачах, а также предлагать ускоренный запуск любых часто выполняемых действий, таких как сохранение нового элемента или выполнение поиска.

Некорректное окрашивание текстовых меток

Стиль элементов пользовательского интерфейса в Sailfish OS указывает, является ли элемент интерактивным. Существует несколько исключений, но, как правило, для кнопок, переключателей, элементов списка и других элементов, реагирующих на нажатие, применяется основной цвет, а для чисто описательных элементов, таких как текстовые метки, заголовки страниц и разделов, применяется цвет подсветки текущей атмосферы.

Для текстовой метки в примере ниже применяется цвет Theme.highlightColor, поскольку метка не является интерактивной:

Dialog {
    Label {
        color: Theme.highlightColor
        text: "Terms of Use. By selecting Accept you agree to..."
        width: parent.width
    }
}

Цвет подсветки должен применяться для меток и значков в момент их нажатия. Первый элемент списка на изображении слева имеет основной цвет даже при нажатии, что не соответствует стилю Sailfish OS. На изображении справа элемент при нажатии, как и ожидается, окрашивается в цвет подсветки:

Такие компоненты Silica со встроенным текстом, как Button, ComboBox и ContextMenu, будут автоматически менять цвет текста при нажатии, но для собственных компонентов необходимо реализовать этот эффект самостоятельно. Например:

ListItem {
    id: listItem
    width: parent.width

    Label {
        text: model.text
        color: listItem.highlighted ? Theme.highlightColor : Theme.primaryColor
    }
}

Дополнительную информацию об оформлении интерактивных элементов управления в Sailfish OS можно получить в описании типа Theme.

Неправильное выравнивание, размер или интервал

Элементы и содержимое пользовательского интерфейса приложения должны быть тщательно выровнены на экране, а размеры элементов и содержимого должны вписываться в стиль Sailfish OS. Использование единых размеров, интервалов и выравнивания очень важно для внешней привлекательности и читаемости приложений.

В приложениях Sailfish OS графические элементы и изображения располагаются вровень с краями страницы (например, изображения в приложении «Галерея» или обложки музыкальных альбомов в приложении «Медиа»). Текст и значки в элементах управления пользовательским интерфейсом, как правило, отделяются от краев страницы с помощью Theme.horizontalPageMargin для правого и левого отступа и Theme.paddingLarge — для верхнего и нижнего.

В элементах управления, содержащих текст, таких как ComboBox, TextField и PageHeader, уже используется Theme.horizontalPageMargin для задания отступов по горизонтали; обычно их можно регулировать с помощью свойств leftMargin и rightMargin (например, PageHeader.leftMargin). При создании собственных элементов пользовательского интерфейса необходимо добавить отступы самостоятельно. В примере ниже Label привязан к общей ширине родительского элемента, затем задаются значения свойств anchors.leftMargin и anchors.rightMargin:

Page {
    Label {
        text: "A very, very, very long sentence that will extend beyond the width of the screen."
        truncationMode: TruncationMode.Fade
        color: Theme.highlightColor

        anchors {
            left: parent.left
            leftMargin: Theme.horizontalPageMargin
            right: parent.right
            rightMargin: Theme.horizontalPageMargin
            verticalCenter: parent.verticalCenter
        }
    }
}

Элементы пользовательского интерфейса, такие как размеры шрифтов и элементов списка, также должны быть верно и последовательно настроены в соответствии со стандартами Sailfish OS. Стилизация выполняется с помощью объекта Theme, который предоставляет набор стандартных размеров, отступов и цветов для оформления содержимого пользовательского интерфейса Sailfish OS.

Дополнительную информацию можно получить в описании типа Theme.

Слишком маленькие области касания

Разработчики иногда имеют тенденцию создавать приложения со слишком маленькими элементами пользовательского интерфейса. Это становится проблемой при использовании интерактивных элементов, поскольку, чтобы успешно попасть по слишком маленькой области касания, от пользователей требуется гораздо больше когнитивных усилий.

Кроме того, у большинства компонентов интерфейса Sailfish OS отсутствуют визуальные границы области касания, поэтому возможны ошибки при нажатии или выполнении других жестов.

Чтобы максимально увеличить область касания элементов, следует увеличить размер MouseArea.

Между областями касания элементов, расположенных столбцом, в ряд или другим способом, интервала нет. Интервал между элементами реализован за счет того, что область элемента меньше его области касания.

Размер интерактивных элементов не должен быть меньше Theme.itemSizeSmall. Но, как правило, размер большинства интерактивных элементов соответствует Theme.itemSizeMedium или больше, в зависимости от их сложности.

Слишком много элементов в вытягиваемом меню

Вытягиваемое меню должно содержать минимальный набор элементов. В традиционной панели инструментов для мобильных приложений невозможно размещение 6-8 элементов. Аналогичные ограничения установлены для вытягиваемого меню Sailfish OS.

Большинство приложений платформы содержат от одного до трех действий, но в PullDownMenu или PushUpMenu рекомендуется добавлять не более четырех.

Отображение неактивных элементов вытягиваемого меню

Некоторые элементы вытягиваемых меню доступны только при выполнении определенных условий. В случае если вытягиваемое меню состоит только из элементов, которые находятся в неактивном состоянии, то все меню целиком должно быть скрыто. Это необходимо для того, чтобы не показывать вытягиваемое меню, которое невозможно использовать.

Ниже приведен пример реализации отображения меню только с активными элементами:

PullDownMenu {
    MenuItem { text: "Remove" }

    visible: playList.selectionCount > 0
}

Отсутствие индикаторов прокрутки

В приложениях Sailfish OS представления могут включать в себя содержимое, которое выходит за пределы отображения на экране. В этом случае необходимо применять индикаторы прокрутки. Они указывают текущее положение окна просмотра и подсказывают количество доступного содержимого за пределами отображения на экране.

Ниже приведен пример добавления вертикального индикатора прокрутки к представлению SilicaListView:

SilicaListView {
    anchors.fill: parent

    VerticalScrollDecorator {}
}

Использование кнопок вместо жестов

В Sailfish OS традиционные кнопки «Подтвердить» и «Отменить» заменяются аналогичными жестами для подтверждения или отмены действия пользователя. Жест справа налево делает ненужной кнопку «Назад», а жест от левого или правого края экрана к центру — кнопки «Выход» и «Домой». Кроме того, вытягиваемое меню заменяет традиционную панель инструментов приложений.

Жесты должны применяться везде, где только возможно, чтобы обеспечить пользовательский опыт (user experience), соответствующий работе со стандартными приложениями платформы Sailfish OS. Для этого следует использовать тип Dialog вместо Page и DialogHeader вместо PageHeader. Обработка жестов и нажатий на кнопки в заголовке диалогового окна осуществляется с помощью обработчиков сигналов accepted и rejected.

Dialog {
    onAccepted: account.logIn()
    onRejected: accountCreationCanceled()

    DialogHeader {
        acceptText: "Подтвердить"
        cancelText: "Отменить"
    }
}

Отсутствие текстовых подсказок для полей ввода

В Sailfish OS текстовое поле должно определять значения свойств placeholderText и label. Если текстовое поле не заполнено, то в нем отображается текст — значение свойства placeholderText. Этот текст помогает пользователю понять какую информацию необходимо ввести в поле. Текст под полем ввода имеет ту же цель, но отображается после того, как пользователь уже ввел текст. Текст под полем ввода является значением свойства label.

Оба эти свойства могут использовать одно и то же значение, например: «First name», «Last name», «Email» и т. д.

Column {
    width: parent.width

    TextField {
        placeholderText: "First name"
        label: "First name"
        width: parent.width
    }
    TextField {
        placeholderText: "Last name"
        label: "Last name"
        width: parent.width
    }
}

Отсутствие конфигурации кнопки Enter

Поскольку нажатие кнопки «Enter» не создает новых строк в однострочном текстовом поле, то можно переопределить ее назначение с помощью свойств типа EnterKey.

Обычно кнопка ввода используется для перевода фокуса клавиатуры на следующее текстовое поле:

TextField {
    label: "Username"
    placeholderText: "Username"
    width: parent.width

    // Разрешать нажатие кнопки «Enter» только при наличии текста
    EnterKey.enabled: text.length > 0

    // Отображать значок «Next», чтобы указать на то, что нажатие кнопки «Enter»
    // переместит  фокус клавиатуры на следующее текстовое поле
    EnterKey.iconSource: "image://theme/icon-m-enter-next"

    // При нажатии кнопки «Enter» фокус клавиатуры переносится
    // на следующее текстовое поле
    EnterKey.onClicked: passwordField.focus = true
}

Если это поле является последним на странице, то кнопку «Enter» можно использовать для сохранения или отправки введенных данных.

TextField {
    label: "Password"
    placeholderText: "Password"
    width: parent.width

    EnterKey.enabled: text.length > 0
    EnterKey.iconSource: "image://theme/icon-m-enter-accept"
    EnterKey.onClicked: account.login()
}

Если подобные действия не применимы, то функция кнопки «Enter» может быть переопределена, чтобы при нажатии на нее происходило закрытие экранной клавиатуры.

TextField {
    label: "Password"
    placeholderText: "Password"
    width: parent.width

    EnterKey.iconSource: "image://theme/icon-m-enter-close"
    EnterKey.onClicked: focus = false
}

Громоздкая иерархия страниц

Стековая модель навигации упрощает иерархическую навигацию внутри приложения. Когда приложению необходимо отобразить страницу с содержимым, новая страница может быть добавлена в стек. Если пользователь запросит возврат к предыдущей странице, то текущая страница может быть удалена из стека, либо другая страница может быть добавлена в стек, чтобы глубже погрузится в иерархию интерфейса пользователя и т. д. Если стек страниц имеет слишком глубокую иерархию, пользователь может запутаться относительно того, где текущий экран находится внутри приложения. Поэтому вместо постоянного добавления страниц в стек рекомендуется заменять текущую страницу на заданную с помощью метода replace().

Например, в приложении «Карты» найденные с помощью строки поиска страницы не добавляются к существующим, а заменяют их. Это позволяет избежать громоздкой (и, в теории, бесконечно растущей) иерархии стека страниц.