Опубликован: 02.04.2013 | Доступ: свободный | Студентов: 987 / 20 | Длительность: 20:18:00
Специальности: Программист
Лекция 7:

Макет

< Лекция 6 || Лекция 7: 12345678

Разные состояния просмотра приложения

Если в чем-то, касающимся макета приложения для Магазина Windows, и можно быть уверенным, так в том, что режим его отображения, весьма вероятно, будет часто меняться. Во-первых, авто-поворот экрана, особенно, на планшетных, переносных устройствах - делает очень простым и быстрым переключение между альбомной и портретной ориентациями экрана (пользователю не придётся столкнуться с настройкой драйвера дисплея). Во-вторых, устройство может быть подключено к внешнему дисплею, а это означает, что приложение нуждается в самостоятельной настройке на различные разрешения, и, возможно, на различные плотности пикселей. В-третьих, у пользователя есть возможность, в альбомном режиме, "прикреплять" приложение у левой или правой части экрана, когда прикрепленное приложение отображается в области шириной в 320 пикселей, а другое приложение выводится в зоне "заполняющего" просмотра, занимая остаток дисплея. Это можно сделать, используя жесты, мышь, или используя сочетания клавиш Win+. (точка), Win+> (Shift+точка). (Для прикрепленного режима требуется, как минимум, дисплей с разрешением 1366х768, иначе он будет отключен).

Вам, определенно, захочется протестировать своё приложение со всеми этими вариантами: состояния просмотра, размеры дисплеев, плотностью пикселей. Работу в разных состояниях просмотра можно тестировать напрямую, на любом компьютере, а вот для двух последних вариантов нужны специальные инструменты, которые предоставляют имитатор Visual Stuido и закладка Устройство (Device) в Blend ,позволяя вам имитировать различные условия. Нас сейчас интересует вопрос, как приложение будет действовать при различных условиях просмотра.

Состояния просмотра

В "Жизненный путь приложений для Магазина Windows: Характеристики платформы Windows 8" были представлены четыре состояния просмотра, вспомнить о них вы можете, посмотрев на Рис. 1.6. Добавим сейчас следующий уровень точности к их описанию, рассмотрев следующую таблицу. Она включает в себя изображения пространства, которое занимают приложения, описания состояний просмотра и идентификаторов этих состояний и в WinRT (в перечислении Windows.UI.ViewManagement.ApplicationViewState (http://msdn.microsoft.com/library/windows/apps/windows.ui.viewmanagement.applicationviewstate.aspx), и в характеристике -ms-view-state (http://msdn.microsoft.com/library/windows/apps/hh465826.aspx) CSS-медиазапросов.

Таблица 6.2.
Пространство, занимаемое приложением (Голубое) Подробности
Приложение занимает весь экран в альбомном режиме. WinRT: fullScreenLandscape -ms-view-state: fullscreen-landscape
Приложение занимает либо левую, либо правую часть экрана в альбомном режиме, на области, ограниченной шириной в 320 пикселей. Это означает, что вам не нужно создавать дизайн для всех возможных размеров среди прикрепленных, заполненных (смотрите ниже) и полноэкранных состояний просмотра. WinRT: snapped -ms-view-state: snapped
Приложение занимает область экрана, находящуюся рядом с прикрепленным приложением. Ширина области, доступной приложению, равняется ширине экрана за вычетом 320 пикселей и 22 пикселей для элемента-разделителя. WinRT: filled -ms-view-state: filled
Приложение в портретном режиме WinRT: fullScreenPortrait -ms-view-state: fullscreen-portrait

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

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

Дизайн приложения, таким образом, включает все режимы просмотра для каждой страницы, так же, как мы поступили с описаниями страниц "Here My Am!" в "Быстрый старт" . В то же время, обработка режимов просмотра для каждой страницы не подразумевает четыре разных реализации приложения. Режимы просмотра это не более чем разные визуальные представления одного и того же содержимого страниц, как описано в "Руководстве по прикрепленному и заполненному представлениям" (http://msdn.microsoft.com/library/windows/apps/hh465371.aspx). Таким образом, переключение между режимами просмотра всегда сохраняет состояние приложения и его страниц - оно никогда не изменяет режим работы приложения или не осуществляет навигацию на другую страницу. Единственное исключение из этого правила сущестует, если приложение по веским причинам не может работать в прикрепленном режиме (как, например, игра, которой нужно определенное экранное пространство). В таком случае приложение может вывести сообщение об этом, вместе с инструкцией вроде "Прикоснитесь здесь, чтобы продолжить", что позволяет пользователю выразить таким образом своё намерение. В ответ на команду пользователя, приложение может вызвать Windows.UI.ViewManagement.Application-View.tryUnsnap, (http://msdn.microsoft.com/library/windows/apps/windows.ui.viewmanagement.applicationview.aspx), как показано в примере "Прикрепленный режим", (http://code.msdn.microsoft.com/windowsapps/Snap-Sample-2dc21ee3)2tryUnsnap - это единственный программный API, который может воздействовать на состояния просмотра. Состояния просмотра, другими словами, всегда меняются по инициативе пользователя, и нет API для установки состояний просмотра, и нет способа для того, чтобы задавать их при запуске приложения.. Не используйте, однако, эту возможность для того, чтобы "срезать углы". Попытайтесь сохранить как можно больше возможностей приложения в прикрепленном режиме.

Подсказка. Воспринимайте прикрепленный режим просмотра как дополнительный, ценный режим, где основная информация страницы по-настоящему заметна. Другими словами, рассматривайте прикрепленный режим как возможность, а не как тяжёлое бремя.

С другой стороны, некоторые приложения вынуждены решать проблему дополнительного пространства по вертикали. Широкоэкранное видео в прикрепленном режиме займёт лишь небольшую частьт этого пространства, оставив место, скажем, для дополнительной информации о видео, рекомендаций, плей-листов и так далее, что обычно не видно, когда видео проигрывается на всём экране. В подобном случае, пользователь найдёт дополнительную информацию, переключившись в прикрепленный режим.

Врезка: Предпочтительная ориентация и блокировка ориентации

Состояния просмотра, с другой стороны, позволяют приложениям запуститься в заданном состоянии или/и заблокировать ориентацию, эффективно игнорируя изменения между альбомным и портретным режимом. Проигрыватель видеофайлов, например, обычно гораздо лучше чувствует себя в альбомном режиме, полагая, что полноэкранный альбомный и полноэкранный портретный режимы абсолютно одинаковы - таким образом, вы можете смотреть видео, лёжа на боку с планшетом, поставленным боком на стул.

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

Для того чтобы сообщить Windows об этих предустановках, установите подходящие флаги в группе параметров Поддерживаемые ориентации (Supported Orientations) на закладке Интерфейс приложения (Application UI) в редакторе манифеста:

Множество подробностей о том, как всё это работает, можно найти в справке по InitialRotationPreference (http://msdn.microsoft.com/library/windows/apps/Hh700342.aspx). Я хочу, кроме того, расссказать о свойствах Windows.Graphics.Display.DisplayProperties.autoRotationPreferences (http://msdn.microsoft.com/library/windows/apps/windows.graphics.display.displayproperties.autorotationpreferences.aspx) и currentOrientation (http://msdn.microsoft.com/library/windows/apps/windows.graphics.display.displayproperties.currentorientation.aspx) дл программного управления ориентацией. Для демонстрации, обратитесь к примеру "Предустановки автоповорота устройства" (http://code.msdn.microsoft.com/windowsapps/Auto-Rotation-Preferences-87ae2902).

Обработка состояний просмотра

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

Лучше всего думать о состояниях просмотра в терминах видимости элементов, их размеров, взаимного расположения на странице. При таком подходе, основная часть работы может быть выполнена посредством CSS-медиа запросы с использованием возможности -ms-view-state. Мы видели это в приложении "Here My Am!" из "Быстрый старт" . Шаблон проекта Приложение таблицы так же это демонстрирует. Вот как этим медиа-запросы выглядят в CSS:

@media screen and (-ms-view-state: fullscreen-landscape) {
/* ... */
}

@media screen and (-ms-view-state: filled) {
/* ... */
}

@media screen and (-ms-view-state: snapped) {
/* ... */
}

@media screen and (-ms-view-state: fullscreen-portrait) {
/* ... */
}

/* Синтаксис для комбинирования медиа-запросов (разделены запятыми) */	
@media screen and (-ms-view-state: fullscreen-landscape),

screen and (-ms-view-state: fullscreen-portrait), screen and (-ms-view-state: filled) {
/* ... */	
}

Кроме того, весьма разумно добавить другие выражения к этим запросам, такие, как and (min-width: "1600px"), так как вы можете выполнять множество различных настроек, основываясь на разрешении экрана.

Для приложений Магазина Windows применяйте возможности обработки режимов просмотра в медиа-запросах вместо состояний, хранящихся в свойстве CSS orientation (альбомная (landscape) и портретная (portrait)), которые просто получаются путём анализа относительной ширины и высоты дисплея и не отличают состояния наподобие прикрепленного (snapped). Другими словами, состояния просмотра в Windows специфичны для платформы и отражают состояния, описаний которых стандартный CSS не имеет, помогая вашему приложению знать не только о доступном ему пространстве экрана, но и о режиме, в котором оно исполняется3Таким образом, состояния просмотра не сообщаются страницам, загруженным в iframe, в веб-контексте. Подобные страницы могут использовать стандартные CSS-медиа запросы для того, чтобы сделать вывод о состоянии просмотра, или окружающая страница, исполняющаяся в локальном контексте, может передать сведения о состоянии просмотра в iframe с помощью postMessage..

Например, следуя стандартному алгоритму CSS, и полноэкранный портретный (fullscreen portrait), и прикрепленный (snapped) режимы детектируются как orientation: portrait, так как соотношение сторон экрана в таких режимах указывает на его вертикальное расположение. Однако, прикрепленный режим подразумевает иное намерение пользователя, чем полноэкранный портретный. В прикрепленном режиме вы скорее хотите видеть наиболее важные части приложения, нежели копию портретного макета в пространстве шириной 320 пикселей.

Обычный подход заключается в том, чтобы размещать правила, касающиеся полноэкранного альбомного режима просмотра, в верхней части CSS-файла и затем выполнять тонкие настройки внутри конкретных медиа-запросов. Мы сделали это с "Here My Am!" в "Быстрый старт" , где стиль по умолчанию работает для режимов fullscreen-landscape и filled, и нам нужно было задать специфические правила лишь для режимов snapped и fullscreen-portrait.

Совет. При стилизации приложения в Blend, в панели Правила стилей (Style Rules)существуют интуитивно понятные визуальные подсказки, которые позволяют контролировать точную точку вставки любого нового CSS-стиля в заданной таблице стилей. С помощью этого средства, которое выглядит как оранжевая линия на рисунке ниже, и как показано в Video 2.2., вы можете указать точное место вставки стилей для конкретных медиа-запросов внутри медиа-запроса.

В некоторых случаях обработка медиа-запросов в декларативном CSS недостататочна. Когда основное содержимое отображается на странице, содержащей ListView с макетом gridLayout, которая прокручивается в горизонтальном направлении, обычно макет переключают на ListLayout при переходе в прикрепленный режим. Вы можете, кроме того, как показано в материале: "Руководство по прикрепленному и заполненному представлениях" (http://msdn.microsoft.com/library/windows/apps/hh465371.aspx), преобразовать список кнопок в единый выпадающий элемент select для того, чтобы предложить пользователю те же функциональные возможности посредством более компактного пользовательского интерфейса. Для реализации подобного вам понадобится JavaScript.

Для подобных целей вы можете задействовать стандартное Media Query Listener API в JavaScript. Данный интерфейс (часть W3C CSSOM View Module, http://dev.w3.org/csswg/cssom-view/) позволяет вам добавлять обработчики к изменениям состояний медиа-запросов. Для того, чтобы прослушивать событие перехода в режим прикрепленного просмотра, вы можете использовать код, подобный этому:

var mql = window.matchMedia("(-ms-view-state: snapped)");
mql.addListener(styleForSnapped);
function styleForSnapped() {
if (mql.matches) {	
//...	
}

// Создайте прослушиватели для других состояний просмотра: full-screen, fill, и device-portrait
// или обработайте все меди-запросы в едином обработчике, проверяя в нём текущее состояние просмотра.

Вы можете видеть, что строка медиа-запроса, которую передают в window.matchMedia, это та же строка, котрая используется в CSS, и в обработчике вы, конечно, можете сделать всё, что нужно с помощью JavaScript.

Совет. Убедитесь в том, что протестировали режимы просмотра приложения при возникновении события resuming, так как характеристики дисплея могут измениться, например, при подключении другого монитора или увеличение экранных элементов, выполненного с помощью команды панели чудо-кнопок Параметры > Изменение параметров компьютера > Специальные возможности (Settings > Change PC Setings > Ease of Access), которая ведет к окну, содержащему тумблер Увеличить все элементы на экране (Make Everything on the Screen Bigger). Воззможно, что ваше приложение будет восстановлено из фонового режима (из приостановленного состояния) в прикрепленный режим просмотра, пока ваше приложение приостановлено, могут поменяться размеры экрана. Поэтому тестируйте макет на корректную обработку события resuming при открытии приложения в прикрепленном режиме просмотра и при изменении параметров экрана.

Обрабатывая изменения режимов просмотра (или события window.onresize), вы можете получить точные размеры окна приложения посредством свойств window.innerWidth и window.innerHeight. Свойства document.body.clientWidth и document.body.clientHeight позволяют узнать ту же информацию, что и из свойств clientWidth и clientHeight любого элемента (наподобие div), который занимает 100% тела документа. Внутри события resize так же доступны свойства args.view.outerWidth и args.view.outerHeight.

В CSS так же доступны сведения о высоте и ширине окна просмотра (vh и vw, соответственно). Вы можете поставить перед ними префикс в виде процентов, например, 100vh - это 100% высоты окна просмотра, и 3.5vw - это 3.5% ширины окна просмотра. Эти переменные так же могут быть использованы в выражениях CSS calc.

Текущий режим просмотра доступен посредством свойства Windows.UI.ViewManagement.ApplicationView.value. Его значения берутся из перечисления Windows.UI.ViewManagement.ApplicationViewState, как показано в вышеприведенной таблице. В предыдущих лекциях мы видели применение этих механизмов. Например, элементы управления страниц (речь о них шла в "Анатомия приложения и навигация по страницам" ) обычно проверяют состояние просмотра в их методе ready и напрямую получают эти состояния в своём методе updateLayout. На самом деле, каждый метод элемента управления страницы groupedItem в проекте Приложение таблицы чувствителен к изменению состояния просмотра. Взгляните на код, взятый из pages/groupedItems/groupedItems.js:

// Несколько строк и комментариев опущено	
var appView = Windows.UI.ViewManagement.ApplicationView;	
var appViewState = Windows.UI.ViewManagement.ApplicationViewState;
var nav = WinJS.Navigation;	
var ui = WinJS.UI;	

ui.Pages.define("/pages/groupedItems/groupedItems.html", {
initializeLayout: function (listView, viewState) {
if (viewState === appViewState.snapped) { listView.itemDataSource = Data.groups.dataSource; listView.groupDataSource = null;
listView.layout = new ui.ListLayout();
} else {
listView.itemDataSource = Data.items.dataSource;
listView.groupDataSource = Data.groups.dataSource;
listView.layout = new ui.GridLayout({ groupHeaderPosition: "top" });
}
},

itemInvoked: function (args) {
if (appView.value === appViewState.snapped) {
// Если страница в прикрепленном режиме, пользователь вызывает группу. 
var group = Data.groups.getAt(args.detail.itemIndex); nav.navigate("/pages/groupDetail/groupDetail.html", { groupKey: group.key });
} else {
// Если страница не в прикрепленном режиме, пользователь активирует элемент. 
var item = Data.items.getAt(args.detail.itemIndex); nav.navigate("/pages/itemDetail/itemDetail.html",
{ item: Data.getItemReference(item) });
}
},

ready: function (element, options) {
// ...	
this.initializeLayout(listView, appView.value);
// ...	
},	
// Эта функция обновляет макет страницы в ответ на изменения viewState. 
updateLayout: function (element, viewState, lastViewState) {
var listView = element.querySelector(".groupeditemslist").winControl;
if (lastViewState !== viewState) {
if (lastViewState === appViewState.snapped ||
viewState === appViewState.snapped) {
var handler = function (e) {
listView.removeEventListener("contentanimating", handler, false);
e.preventDefault();
}
listView.addEventListener("contentanimating", handler, false);
this.initializeLayout(listView, viewState);
}
}
}
}
});

В первую очередь, метод initializeLayout, который вызывается и из ready и из updateLayout проверяет текущее состояние просмотра и соответствующим образом настраивает элемент управления ListView. Если вы помните из "Коллекции и элементы управления для вывода коллекций" , во время исполнения программы можно и настраивать ListView и менять его источник данных. Здесь мы используем ListLayout со списком групп в прикрепленном состоянии просмотра и gridLayout со сгруппированными элементами в других режимах. Это показывает, как мы показываем то же самое содержимое, но в более сжатом формате, скрывая отдельные элементы в прикрепленном режиме. Из-за этого itemInvoked так же проверяет режим отображения, так как элементы списка - это группы в прикрепленном режиме и в таком случае навигация осуществляется на страницу сведений о группе вместо перехода на страницу детальной информации об элементе.

Что касается updateLayout, он активируется из обработчика события window.onresize в коде PageControlNavigator (смотрите js/navigator.js в шаблоне проекта Приложение таблицы). Этот обработчик передаёт сведения о новом и предыдущем состоянии просмотра в updateLayout. Если эта функция обнаруживает, что мы переключились в прикрепленный режим или переключились из него, она сбрасывает к исходному состоянию ListView посредством initializeLayout. И, так как мы меняем источник данных ListView, здесь нет нужды в воспроизведении анимации входа или перехода. Небольшая уловка, работающая с событием contentanimating просто подавляет анимацию.

Врезка: Физическая ориентация экрана

Полноэкранный альбомный и полноэкранный портретный режимы просмотра предоставляют некоторую информацию о том, как устройство, на самом деле, ориентировано в пространстве, но подобная информация может быть гораздо точнее получена из свойств объекта Windows.Graphics.Display.DisplayProperties (http://msdn.microsoft.com/library/windows/apps/windows.graphics.display.displayproperties.aspx). В частности, свойство currentOrientation содержит значение из перечисления Windows.Graphics.Display.DisplayOrientations (http://msdn.microsoft.com/library/windows/apps/windows.graphics.display.displayorientations.aspx), что показывает, как устройство повёрнуто по отношению к nativeOrientation (и вызывает, при необходимости, событие orientationchanged). Эти данные позволят вам узнать, например, находится ли устройство экраном вниз, по отношению к небу, что может быть полезным для любого приложения, реализующего дополненную реальность, такую, как звёздная карта.

Похожим образом, API Windows.Devices.Sensors (http://msdn.microsoft.com/library/windows/apps/windows.devices.sensors.aspx), в частности классы, SimpleOrientationSensor и OrientationSensor могут предоставить больше информации от сенсоров. Разговор об этом пойдёт в "Анатомия приложения и навигация по страницам" курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript".

< Лекция 6 || Лекция 7: 12345678
Екатерина Вальковская
Екатерина Вальковская
Россия, г. Кемерово