Платформа WinRT, под управлением которой выполняются приложения Windows Store, предоставляет разработчику разнообразные готовые решения если не на все, то на очень многие случаи жизни. Так, разработчик может буквально несколькими строками кода реализовать в своём приложении загрузку или отправку файлов по сети, поиск данных по введённому пользователем ключевому слову, печать данных в удобном для пользователя виде и поддержку жестов, как совсем простых, наподобие касания экрана, так и сложных, выполняемых несколькими пальцами.
Существует и готовое решение для создания настраиваемых приложений. Разработчику для этого достаточно лишь определить набор элементов управления, "ответственных" за настройки приложения, создать несколько дополнительных элементов интерфейса и добавить десяток строк кода в логику. Всё остальное берёт на себя WinRT.
Эта статья будет посвящена созданию настраиваемых приложений.
Внимание! Перед чтением следует ознакомиться с предыдущими статьями из цикла "Начала Metro-программирования", опубликованными на нашем сайте ранее. Описанные в них приёмы программирования будут активно здесь использоваться.
1. Настройки приложения - способы реализации
Чтобы дать приложению возможность настройки, прежде всего следует создать набор элементов управления, с помощью которых пользователь будет задавать параметры приложения: флажков, переключателей, списков, полей ввода и пр. Эти элементы управления следует как-то вывести на экран.
Как? Применив один из трёх способов, перечисленных далее.
Разместив эти элементы управления прямо в основном интерфейсе приложения или на какой-либо из его страниц. (О страницах рассказывалось в одной из предыдущих статей цикла.)
Достоинство такого подхода одно - все нужные элементы управления доступны сразу же после запуска приложения. Недостаток - элементы управления, относящиеся к настройкам и по определению используемые нечасто, большую часть времени лишь впустую занимают экранное пространство, которое можно отвести под что-то более насущное. К тому же, размещение настройки прямо в основном интерфейсе приложения не вписывается в стиль разработки Windows Store.
На практике такой подход используется очень редко и только для тех настроек, которые изменяются достаточно часто.
Поместив настройки во всплывающем элементе или вынеся их во всплывающее или контекстное меню. (О всплывающих элементах и меню рассказывалось в статье, посвящённой созданию интернет-приложений.)
Достоинство такого подхода - настройки не занимают место на экране, однако до них можно добраться одним-двумя касаниями. Существенных недостатков у этого подхода нет, за исключением того, что размещение настроек во всплывающих элементах, опять же, не вписывается в стиль разработки Windows Store.
Тем не менее, этот подход иногда используется на практике, в основном, в простых приложениях с небольшим количеством доступных настроек.
Поместив настройки в особую панель настроек WinRT (рис. 1), аналогичную панелям поиска и печати (о которых рассказывалось в предыдущих статьях). Такой подход имеет то же достоинство, что и предыдущий, и, вдобавок к этому, полностью соответствует стилю разработки Windows Store. Этот подход рекомендуется применять в большинстве случаев.
Рис. 1. Панель настроек WinRT - список секций (запущено приложение Internet Explorer)
Панель настроек изначально содержит список так называемых секций - разделов, содержащих настройки, что относятся к разным аспектам функционирования данного приложения (рис. 1). Например, в случае видеопроигрывателя одна такая секция может содержать настройки воспроизведения фильма, другая - настройки внешнего вида приложения, третья - настройки его поведения в ответ на жесты и т. д.
Чтобы перейти к собственно нужной секции, достаточно нажать на соответствующую ей строку списка (рис. 2).
Давайте дадим возможность настройки написанному нами ранее приложению видеопроигрывателя. Пусть оно по желанию пользователя рапускает файл на воспроизведение сразу после его открытия и перематывает фильм в начало по окончанию его воспроизведения.
2. Реализация панели настроек и её секций
Как реализовать настройку приложении через соответствующую панель WinRT? Очень просто!
2.1. Интерфейс секций панели настроек
Интерфейс такой секции описывается в HTML-коде интерфейса приложения, что вполне логично. Как и все остальные элементы управления WinRT, она создаётся на основе блока (тега <div>), который, таким образом, станет элементом-основой для секции. А представляется она экземпляром объекта WinJS.UI.SettingsFlyout, чьё имя мы обязательно укажем в атрибуте тега data-win-control.
<div id="sftMain" data-win-control="WinJS.UI.SettingsFlyout">
<!-- Элементы управления, которые будут входить в состав секции панели настройки -->
</div>
ии панели настройки -->
</div>[/code]
Внутри тега <div>, формирующего элемент-основу для секции, пишется HTML-код, создающий все элементы управления, которые будут "отвечать" за настройки, что входят в состав данной секции. Это могут быть любые элементы управления HTML или WinRT.
Объект WinJS.UI.SettingsFlyout поддерживает два свойства, которые обязательно нам пригодятся:
settingsCommandId - задаёт уникальный идентификатор для данной секции в виде строки. Отметим, что задавать его следует обязательно, иначе WinRT не сможет обработать эту секцию.
width - задаёт ширину секции в виде одной из двух предопределённых строковых значений: "narrow" ("узкая", шириной 346 пикселов) и "wide" ("широкая", шириной 646 пикселов). Значение по умолчанию - "narrow".
[code]<div id="sftMain" data-win-control="WinJS.UI.SettingsFlyout"
data-win-options="{settingsCommandId: 'scmMain'}">
<div id="tglPlayOnOpen" data-win-control="WinJS.UI.ToggleSwitch"
data-win-options="{title: 'Запускать воспроизведение после открытия файла'}"></div>
<div id="tglRewindOnEnd" data-win-control="WinJS.UI.ToggleSwitch"
data-win-options="{title: 'Перематывать в начало по завершении воспроизведения'}"></div>
</div>[/code]
Здесь мы создали в секции два переключателя WinRT, первый из которых управляет функцией автоматического запуска воспроизведения файла после его открытия, а второй - функцией перемотки фильма по окончанию его воспроизведения. И задали для секции идентификатор scmMain.
2.2. Формирование и вывод панели настроек
Но описать интерфейс для секций панели настроек - только полдела. Нам ещё нужно сформировать панель настроек на основе созданных нами секций и реализовать вывод её на экран.
Любое приложение WinRT представляется объектом WinJS.Application. Этот объект предоставляет набор свойств и методов, позволяющих получать параметры приложения и управлять им, и событий, которые возникают в самом приложении и на которые мы можем как-то реагировать.
Нас интересует событие settings, возникающее, когда пользователь инициирует вывод на экран панель настроек. Его обработчик в качестве единственного параметра получает экземпляр объекта CustomEvent, хранящий сведения о возникшем событии.
Свойство detail этого объекта хранит дополнительные сведения о событии в виде экземпляра объекта Object. Его свойство applicationcommands должно получить список всех секций, что должны присутствовать в панели настроек. Этот список также должен представлять собой экземпляр объекта Object; его свойства должны представлять собой строковые идентификаторы секций, а значения - сведения об этих секциях. Сведения о секциях должны представлять собой экземпляры объекта Object с единственным свойством title, задающим заголовки секций.
Задав список секций, мы вызовем не возвращающий результата метод populateSettings объекта WinJS.UI.SettingsFlyout, передав ему в качестве единственного параметра экземпляр объекта CustomEvent. полученный обработчиком события. Отметим, что данный метод вызывается у самого объекта WinJS.UI.SettingsFlyout, а не у его экземпляра, то есть является методом объекта.
В начале кода логики сам Visual Studio вставляет вот такое выражение:
[code]var app = WinJS.Application;[/code]
Оно присваивает объект WinJS.Application переменной app. Так что мы можем обращаться впоследствии к этой переменной вместо того, чтобы писать каждый раз полное имя объекта.
[code]app.onsettings = function (e) {
e.detail.applicationcommands = {
"scmMain": { title: "Настройки" }
};
WinJS.UI.SettingsFlyout.populateSettings(e);
};[/code]
Здесь мы формируем панель настройки на основе единственной созданной нами секции scmMain и задаём для неё незатейливый заголовок "Настройки".
2.3. Требования к секциям панели настроек
А теперь самое время рассмотреть требования, предъявляемые к секциям панели настроек. Несоблюдение этих требований может вызвать отказ в публикации нашего приложения в магазине Windows Store.
Прежде всего, все настройки, сделанные в панели, должны применяться сразу же, без необходимости в нажатии кнопки "Применить" или "ОК"; более того, никакие командные кнопки в панели настроек не допускаются. Так, если мы в настройках видеопроигрывателя включим режим автоматического запуска воспроизведения после открытия файла, то эта установка должна действовать уже при открытии следующего файла.
Далее, сам вид панели настроек должен настраивать пользователя на то, что все сделанные здесь настройки будут применены немедленно. Во-первых, как уже упоминалось, здесь должны отсутствовать любые кнопки "Применить" или "ОК", равно как и кнопки "Отмена". Во-вторых, рекомендуется использовать специфические элементы управления, предоставляемые WinRT для таких случаев; так, вместо флажков следует применять переключатели WinRT (как это сделали мы).
Каждая секция должна включать в свой состав заголовок, кнопку возврата в панель настроек и небольшой графический логотип приложения. Это позволит пользователю всегда знать, на какой секции какого приложения он находится, и без проблем вернуться в список секций.
Наконец, содержимое каждой секции для удобства пользователя следует разбивать на разделы. Эти разделы формируются с помощью обычных блоков (тегов <div>), к которым привязываются особые стилевые классы. Поговорим об этом подробнее.
Самый первый раздел включает заголовок, кнопку возврата и логотип. К нему привязывается стилевой класс win-header и win-ui-dark (если выбрана "тёмная" тема оформления; в случае применения "светлой" темы следует выбрать стилевой класс win-ui-light).
Заголовок секции формируется блоком, к которому привязывается стилевой класс win-label. Кнопка возврата создаётся пустым тегом <button>, к которому привязывается стилевой класс win-backbutton. Графический логотип, как обычно, формируется тегом <img>; для него устанавливается абсолютное позиционирование и расстояние между правым краем самого логотипа и правым краем секции, равное 40 пикселам. Файл, где хранится этот логотип, находится в папке images и носит имя smalllogo.png.
Следующий раздел отводится под собственно содержимое секции - элементы управления, соответствующие всем доступным здесь настройкам. К нему привязывается стилевой класс win-content.
Если секция содержит множество элементов управления, их можно разделить на функциональные группы. Такие группы формируются блоками, к которым привязывается стилевой класс win-settings-section.
Давайте переделаем созданную ранее секцию с учётом всего вышесказанного. Формирующий её HTML-код будет таким:
[code]<div id="sftMain" data-win-control="WinJS.UI.SettingsFlyout"
data-win-options="{settingsCommandId: 'scmMain'}">
<div class="win-ui-dark win-header">
<button id="btnSettingsBack" class="win-backbutton"></button>
<div class="win-label">Настройки</div>
<img src="/images/smalllogo.png" style="position: absolute; right: 40px;"/>
</div>
<div class="win-content">
<div id="tglPlayOnOpen" data-win-control="WinJS.UI.ToggleSwitch"
data-win-options="{title: 'Запускать воспроизведение после открытия файла'}"></div>
<div id="tglRewindOnEnd" data-win-control="WinJS.UI.ToggleSwitch"
data-win-options="{title: 'Перематывать в начало по завершении воспроизведения'}"></div>
</div>
</div>[/code]
Единственное - мы не использовали здесь группы, так как настроек в нашем приложении совсем немного.
2.4. Инициализация секции панели настроек и реагирование на их изменение
Перед тем как секция панели настроек будет выведена на экран, нам следует установить во все её элементы управления значения, отражающие текущие настройки. А также как-то отреагировать на изменение этих значений пользователем.
Установить изначальные значения элементов управления проще всего в обработчике события beforeshow секции настроек (объекта WinJS.UI.SettingsFlyout). Это событие возникает перед тем, как секция выводится на экран.
[code]var bPlayOnOpen = true;
var bRewindOnEnd = true;
. . .
var sftMain = document.getElementById("sftMain").winControl;
var tglPlayOnOpen = document.getElementById("tglPlayOnOpen").winControl;
var tglRewibdOnEnd = document.getElementById("tglRewindOnEnd").winControl;
sftMain.addEventListener("beforeshow", function() {
tglPlayOnOpen.checked = bPlayOnOpen;
tglRewindOnEnd.checked = bRewindOnEnd;
});[/code]
В переменных bPlayOnOpen и bRewindOnEnd хранятся текущие значения настроек; значение true означает, что данная функция включена, значение false - отключена. Свойство checked переключателя WinRT хранит его состояние: включен ли он (значение true) или отключен (значение false).
А отслеживать изменения настроек можно в обработчиках событий, возникающих при изменении состояния соответствующего элемента управления. Для переключателя WinRT это событие change.
[code]tglPlayOnOpen.addEventListener("change", function() {
bPlayOnOpen = tglPlayOnOpen.checked;
});
tglRewindOnEnd.addEventListener("change", function() {
bRewindOnEnd = tglRewindOnEnd.checked;
});[/code]
Здесь мы просто присваиваем переменным, где хранится текущие настройки, состояние соответствующих переключателей. В других случаях может потребоваться выполнять какие-либо ещё действия, например, изменить интерфейс приложения или внести изменения в его работу.
2.5. Прочие инструменты для управления секциями панели настроек
Секция панели настроек, а точнее, реализующий её объект WinJS.UI.SettingsFlyout, поддерживает ещё несколько свойств, методов и событий, которые могут быть нам полезны.
Методы show и hide позволяют, соответственно, вывести секцию на экран и скрыть её. Они не принимают параметров и не возвращают результата. Отметим, что оба этих метода вызываются у самого объекта WinJS.UI.SettingsFlyout, а не у его экземпляров.
[code]WinJS.UI.SettingsFlyout.show();[/code]
Ранее мы поместили в состав секции панели настроек кнопку возврата к списку секций. Реализовать этот возврат мы можем вызовом метод show.
[code]var btnSettingsBack = document.getElementById("btnSettingsBack");
btnSettingsBack.addEventListener("click", function() {
WinJS.UI.SettingsFlyout.show();
});[/code]
Свойство hidden возвращает значение true, если секция в данный момент скрыта, и false, если она присутствует на экране.
События aftershow, beforehide и afterhide возникают, соответственно, после вывода, перед скрытием и после скрытия секции.
2.6. Реализация настроек в приложении видеопроигрывателя
Теперь мы знаем достаточно, чтобы реализовать в написанном ранее приложении видеопроигрывателя возможность настроек.
Откроем в Visual Studio проект VideoPlayer. Откроем файл default.html, где описывается интерфейс приложения, и вставим в самый конец содержимого тега <body> вот такой код:
[code]<div id="sftMain" data-win-control="WinJS.UI.SettingsFlyout"
data-win-options="{settingsCommandId: 'scmMain'}">
<div class="win-ui-dark win-header">
<button id="btnSettingsBack" class="win-backbutton"></button>
<div class="win-label">Настройки</div>
<img src="/images/smalllogo.png" style="position: absolute; right: 40px;"/>
</div>
<div class="win-content">
<div id="tglPlayOnOpen" data-win-control="WinJS.UI.ToggleSwitch"
data-win-options="{title: 'Запускать воспроизведение после открытия файла'}"></div>
<div id="tglRewindOnEnd" data-win-control="WinJS.UI.ToggleSwitch"
data-win-options="{title: 'Перематывать в начало по завершении воспроизведения'}"></div>
</div>
</div>[/code]
Этот код нам уже знаком.
Откроем файл default.js, где пишется логика приложения, и сразу же объявим необходимые переменные:
[code]var bPlayOnOpen = true;
var bRewindOnEnd = true;
var tglPlayOnOpen, tglRewindOnEnd;[/code]
Первые две переменные будут хранить текущее состояние настроек, а последние - переключатели WinRT, которые будут "отвечать" за эти настройки.
Далее найдём код инициализации и внесём в него следующие изменения (вставленный код выделен комментариями):
. . .
});
});[/code]
Здесь мы получаем доступ к вновь добавленным элементам интерфейса и привязываем к ним обработчики событий. Также мы привязываем обработчик к событию ended видеопроигрывателя (оно возникает при завершении воспроизведения фильма) - в этом обработчике мы будем выполнять перемотку фильма в начало.
Напишем код, который заполнит панель настроек секциями и инициирует её вывод:
[code]app.onsettings = function (e) {
e.detail.applicationcommands = {
"scmMain": { title: "Настройки" }
};
WinJS.UI.SettingsFlyout.populateSettings(e);
};[/code]
Изменим код функции vidMainCanPlay - обработчика события canplay видеопроигрывателя. (Это событие возникает, как только видеопроигрыватель посчитает, что он может успешно и без прерываний запустить воспроизведение фильма.) Как обычно, вставленный код выделен соответствующими комментариями.
[code]function vidMainCanPlay() {
. . .
showTiming();
//Вставленный код - начало
if (bPlayOnOpen) {
vidMain.play();
}
//Вставленный код - конец
}[/code]
Вставленный код проверяет, задал ли пользователь автоматический запуск воспроизведения после открытия файла (хранит ли переменная bPlayOnOpen значение true), и, если это так, запускает воспроизведение.
Напишем обработчик события ended видеопроигрывателя:
[code]function vidMainEnded() {
if (bRewindOnEnd) {
vidMain.currentTime = 0;
}
}[/code]
Он проверяет, указал ли пользователь автоматическую перемотку фильма в начало по завершению его воспроизведения (хранит ли переменная bRewindOnEnd значение true), и, если это так, выполняет эту перемотку.
Напишем обработчики событий секции панели настроек и обоих переключателей:
[code]function sftMainBeforeShow() {
tglPlayOnOpen.checked = bPlayOnOpen;
tglRewindOnEnd.checked = bRewindOnEnd;
}
function tglPlayOnOpenChange() {
bPlayOnOpen = tglPlayOnOpen.checked;
}
function tglRewindOnEndChange() {
bRewindOnEnd = tglRewindOnEnd.checked;
}[/code]
Осталось написать функцию, которая выполнится при нажатии кнопки возврата:
[code]function btnSettingsBackClick() {
WinJS.UI.SettingsFlyout.show();
}[/code]
Сохраним исправленные файлы и запустим приложение на выполнение. Попробуем вызвать на экран панель настроек, переключимся в её единственную секцию, посмотрим на неё (рис. 3) и изменим какие-либо настройки. Далее откроем любой видеофайл и посмотрим, действуют ли эти настройки на приложение.
Сайт является источником уникальной информации о семействе операционных систем Windows и других продуктах Microsoft. Перепечатка материалов возможна только с разрешения редакции.
Работает на WMS 2.34 (Страница создана за 0.036 секунд (Общее время SQL: 0.015 секунд - SQL запросов: 53 - Среднее время SQL: 0.00029 секунд))