Передать на печать

Начала Metro-программирования: обработка сложных жестов

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

Но... "Эка невидаль," - скажете вы. - "Отследить нажатие кнопки мыши. Да мы занимались этим ещё сто лет назад". И будете правы.

Вся прелесть приложений Windows Store (ранее они носили название Metro-приложений) - в поддержке сложных, "многопальцевых" жестов - масштабирования и поворота. Ведь современные планшетные компьютеры (а именно для них, в первую очередь, и предназначены такие приложения) позволяют обрабатывать касания экрана сразу несколькими пальцами. И грех этим не воспользоваться!

Но что нам может предложить в этом плане Windows 8? (Точнее, подсистема, исполняющая приложения Windows Store; ранее она называлась платформой Metro.) О, очень многое!

Мы можем указать для любого элемента интерфейса поддержку определённых жестов, просто добавив одну строчку в код его оформления - в привязанный к нему стиль CSS. И, наоборот, мы можем таким же образом запретить элементу управления реагировать на жесты, если нам это не нужно или если мы хотим обрабатывать их в коде логики.

И, как только что было упомянуто, мы можем обрабатывать сложные жесты программно - в коде логики приложения. Для этого Windows 8 предоставит нам высокоуровневые инструменты, избавляющие нас от необходимости отслеживать каждое касание и перемещение каждого пальца. Мы будем получать уже обработанные данные о жесте - величины смещения, масштаба и угла поворота, после чего нам останется только соответственно изменить параметры элемента интерфейса. Для чего нам потребуется написать не так уж и много кода.

Что-то автор заболтался... Давайте, что ли, начнём разговор по существу?..


1. Базовые средства для обработки жестов

Начнём с самого простого - с базовых средств поддержки жестов, реализуемых на декларативном уровне. Или, другими словами, средств, активизируемых через специфические атрибуты стиля CSS в описании оформления приложения.


1.1. Включение поддержки жестов

Чтобы какой-либо элемент интерфейса, не поддерживающий жестов изначально, получил их поддержку, нам следует явно это указать. Для чего мы используем атрибут стиля -ms-touch-action.

Внимание!
Имена многих атрибутов стиля, что мы здесь рассмотрим, начинаются с "фирменного" префикса -ms-. Этот префикс добавляется ко всем атрибутам стиля, либо вообще не описанным в стандартах CSS, что разрабатываются комитетом W3C, либо на данный момент документированным начерно. Впоследствии, после выхода окончательной версии стандарта CSS3, этот префикс может пропасть из имён атрибутов стиля; так, упомянутый ранее атрибут стиля будет называться touch-action.

-ms-touch-action: auto | none | ( pan-x || pan-y || pinch-zoom ) | manipulation



Поддерживаемые им значения перечислены далее.

  • auto - поддержкой жестов элементом интерфейса "заведует" сама Windows 8 (поведение по умолчанию).
  • none - элемент вообще не поддерживает жестов.
  • pan-x - элемент поддерживает жесты перемещения по горизонтали.
  • pan-y - элемент поддерживает жесты перемещения по вертикали.
  • pinch-zoom - элемент поддерживает жесты изменения масштаба (увеличения и уменьшения).
  • manipulation - элемент поддерживает жесты перемещения по горизонтали и вертикали и изменения масштаба (фактически комбинация значений pan-x, pan-y и pimch-zoom).



Значения pan-x, pan-y и pinch-zoom можно комбинировать друг с другом, указывая таким образом, скажем, поддержку перемещения по горизонтали и масштабирования.

Значения auto, none, одно или комбинация значений pan-x, pan-y и pinch-zoom и значение manipulation являются взаимоисключающими, то есть можно указать только одно из них.

Атрибут стиля -ms-touch-action указывается в стиле, который привязывается непосредственно к элементу интерфейса, которому следует дать поддержку жестов. Что, впрочем, вполне очевидно...

Перемещение и масштабирование элемента интерфейса выполняется относительно его ближайшего родителя.

.divListItem { -ms-touch-action: pan-y; }



Даём элементам интерфейса с привязанным стилевым классом divListItem возможность перемещения по вертикали. Эти элементы могут быть, скажем, пунктами списка.

.divGridItem { -ms-touch-action: pan-x pan-y; }



А элементы интерфейса с привязанным стилевым классом divGridItem можно будет перемещать и по горизонтали, и по вертикали.


1.2. Задание дополнительных параметров

Ещё Windows 8 позволяет нам задать дополнительные параметры поведения элементов интерфейса в процессе обработки ими жестов. Таких параметров довольно много.


1.2.1. Дополнительные параметры прокрутки

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

Для указания, как элемент интерфейса будет вести себя в случае переполнения (то есть выхода содержимого элемента за его границы), предназначены атрибуты стиля overflow, overflow-x и overflow-y. Первый атрибут стиля задаёт поведение элемента при переполнении по ширине и высоте, второй - только по ширине, а третий - только по высоте.

Внимание!
В соответствующем разделе MSDN последние два атрибута стиля носят названия -ms-overflow-x и -ms-overflow-y. Но, насколько удалось выяснить автору, реально поддерживаются именно атрибуты стиля overflow-x и overflow-y.

overflow | overflow-x | overflow-y: visible | scroll | auto | hidden

Здесь мы видим четыре доступных значения:

  • visible — соответствующий размер элемента увеличится, чтобы полностью вместить всё содержимое (обычное поведение). Однако в этом случае часть элемента может оказаться за краем экрана или другого элемента интерфейса, и добраться до скрытой части содержимого не получится;
  • scroll — в элементе появятся полосы прокрутки, с помощью которых пользователь сможет выполнить прокрутку содержимого элемента. Эти полосы прокрутки будут присутствовать в элементе всегда, даже если в них нет нужды;
  • auto — то же самое, что scroll, но полосы прокрутки появятся только в том случае, только если в них действительно возникнет необходимость;
  • hidden — не помещающееся в элемент содержимое будет скрыто, и добраться до него не получится.



#divList { overflow-y: auto; }



Задаём для элемента интерфейса с именем divList возможность прокрутки по вертикали, причём полосы прокрутки появятся только в случае, если содержимое действительно не будет помещаться в элементе по высоте.

Четыре следующих атрибута стиля позволяют задать минимальные и максимальные значения прокрутки по горизонтали и вертикали:

  • -ms-scroll-limit-x-min - минимальное значение прокрутки по горизонтали;
  • -ms-scroll-limit-x-max - максимальное значение прокрутки по горизонтали;
  • -ms-scroll-limit-y-min - минимальное значение прокрутки по вертикали;
  • -ms-scroll-limit-y-max - максимальное значение прокрутки по вертикали.



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

#divList {
  -ms-scrol-limit-y-min: 10%;
  -ms-scrol-limit-y-max: 90%;
}



Атрибут стиля -ms-scroll-limit позволяет задать все четыре значения предельных величин прокрутки за один раз:

-ms-scroll-limit: <минимальное по горизонтали> <минимальное по вертикали> <максимальное по горизонтали> <максимальное по вертикали>

максимальное по горизонтали> <максимальное по вертикали>[/code]

[code]#divList { -ms-scrol-limit: 0% 10% 100% 90%; }[/code]

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

Сначала нам следует задать режим скачкообразной прокрутки, для чего мы воспользуемся атрибутом стиля -ms-scroll-snap-type.

[code]-ms-scroll-snap-type: none | proximity | mandatory[/code]

Он поддерживает три значения:

  • none — выполняется плавная прокрутка (значение по умолчанию);
  • proximity — применяется скачкообразная прокрутка, причём пользователь всё же имеет возможность прокрутить содержимое до произвольной точки, находящейся между указанными нами позициями;
  • mandatory — применяется скачкообразная прокрутка, но пользователь не может прокрутить содержимое до произвольной позиции - только до одной из указанных нами.



[code]#divList { -ms-scrol-snap-type: proximity; }[/code]

Сам набор фиксированных позиций прокрутки указывается при помощи атрибутов стиля -ms-scroll-snap-points-x и -ms-scroll-snap-points-y:

[code]-ms-scroll-snap-points-x | -ms-scroll-snap-points-y: <интервал между отдельными позициями> | <список произвольных позиций>[/code]

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

  • Начальная позиция и интервал между остальными — предыдущими и последующими — позициями прокрутки указывается с применением функции CSS snapInterval в таком формате:

    [code]snapInterval(<начальная позиция>, <интервал>)[/code]

    Оба значения могут быть заданы в любых единицах измерения, поддерживаемых CSS.

    [code]#divList { -ms-scroll-snap-points-y: snapInterval(0px, 100px); }[/code]

    Начальная позиция будет равно 0 пикселов (то есть самое начало содержимого элемента), а остальные позиции будут отстоять друг от друга на 100 пикселов.
  • Список произвольных позиций указывается с помощью функции CSS snapList в таком формате:

    [code]snapList(<позиция 1>, <позиция 2> . . .)[/code]

    Позиции задаются в любых единицах измерения, поддерживаемых CSS.

    [code]#divList { -ms-scroll-snap-points-y: snapList(0px, 100px, 200px, 400px, 100%); }[/code]

    Дадим пользователю возможность прокрутить содержимое элемента с самого начала (0 пикселов), до отметок 100, 200, 400 пикселов и самого конца (100%).



Атрибуты стиля -ms-scroll-snap-x и -ms-scroll-snap-y позволяют задать сразу все параметры скачкообразной прокрутки отдельно для горизонтального и вертикального направлений соответственно.

[code]-ms-scroll-snap-x | -ms-scroll-snap-y[/code]: <режим прокрутки> <список позиций прокрутки>[/code]

[code]#divList { -ms-scroll-snap-y: proximity snapInterval(0px, 100px); }[/code]

Если для какого-либо элемента интерфейса указана возможность прокрутки в обоих направлениях - и по горизонтали, и по вертикали, - по умолчанию прокрутка может выполняться в произвольном направлении, в том числе и по диагонали. Однако мы можем указать прокрутку строго по горизонтальной и вертикальной координатным осям; при этом случайные движения пальца в направлении, перпендикулярном направлению прокрутки, будут игнорироваться. Активизировать такой режим мы можем с помощью атрибута стиля -ms-scroll-rails.

[code]-ms-scroll-rails: none | railed[/code]

Значение none разрешает свободную прокрутку (поведение по умолчанию), а значение railed задаёт прокрутку строго по координатным осям.

[code]#divList { -ms-scroll-rails: railed; }[/code]

Ещё нам может пригодиться атрибут стиля -ms-overflow-style, задающий вид полос прокрутки.

[code]-ms-overflow-style: scrollbar | -ms-autohiding-scrollbar | none | auto[/code]

Он поддерживаются четыре возможных значения:

  • scrollbar - выводятся обычные полосы прокрутки, знакомые нам по предыдущим версиям Windows. Отметим, что такие полосы прокрутки требуют дополнительного простраства внутри элемента для своего отображения.
  • -ms-autohiding-scrollbar - выводятся полосы прокрутки в стиле Windows Store, автоматически появляющиеся на экране и так же автоматически скрывающиеся. Они не требуют для отображения никакого дополнительного пространства, так как выводятся поверх остального содержимого элемента.
  • none - полосы прокрутки вообще не выводятся. Однако содержимое элемента всё же может прокручиваться пальцем или колёсиком мыши.
  • auto - в случае приложений Windows Store то же самое, что и значение -ms-autohiding-scrollbar.



[code]#divList: { -ms-overflow-style: scrollbar; }[/code]

Задаём для элемента divList "старые" полосы прокрутки. Хотя для приложений Windows Store настоятельно рекомендуется использовать полосы прокрутки в "новом" стиле.


1.2.2. Дополнительные параметры масштабирования

Как и в случае перемещения, чтобы содержимое какого-либо элемента интерфейса могло масштабироваться в результате обработки жестов, нам потребуется явно это указать. В этом нам поможет атрибут стиля -ms-content-zooming.

[code]-ms-content-zooming: none | zoom[/code]

Значение none указывает, что элемент не будет масштабироваться; это значение по умолчанию. А значение zoom делает элемент масштабируемым с помощью жестов.

[code]#divZoom { -ms-content-zooming: zoom; }[/code]

Теперь содержимое элемента divZoom будет масштабироваться в ответ на соответствующие жесты.

Атрибуты стиля -ms-content-zoom-limit-min и -ms-content-zoom-limit-max задают, соответственно, минимальное и максимальное значения масштаба, которые может установить пользователь для содержимого данного элемента.

[code]-ms-content-zoom-limit-min | -ms-content-zoom-limit-max: <масштаб>[/code]

Здесь допускаются только относительные значения масштаба, заданные в процентах.

[code]#divZoom {
-ms-content-zoom-limit-min: 10%;
-ms-content-zoom-limit-max: 400%;
}[/code]

Теперь пользователь сможет менять масштаб содержимого элемента divZoom строго в диапазоне 10-400%.

Атрибут стиля -ms-content-zoom-limit позволит нам указать сразу и минимальное, и максимальное значения масштаба:

[code]-ms-content-zoom-limit: <минимальный масштаб> <максимальный масштаб>[/code]

[code]#divZoom { -ms-content-zoom-limit: 10% 400%; }[/code]

Как и прокрутка, масштабирование может выполняться как плавно, так и скачкообразно. Задать скачкообразное масштабирование мы можем, применив атрибуты стиля -ms-content-zoom-snap-type и -ms-content-zoom-snap-points. Первый атрибут стиля задаёт режим масштабирования и поддерживает те же значения, что и знакомый уже нам атрибут стиля -ms-scroll-snap-type. Второй же устанавливает набор позиций масштаба; его значения указываются в таком же формате, что и у атрибутов стиля -ms-scroll-snap-points-x и -ms-scroll-snap-points-y.

[code]#divZoom {
-ms-content-zoom-snap-type: proximity;
-ms-content-zoom-snap-points: snapList(10%, 50%, 75%, 100%, 200%, 400%);
}[/code]

А атрибут стиля -ms-content-zoom-snap позволит нам указать сразу все параметры скачкообразного масштабирования.

[code]-ms-content-zoom-snap: <режим скачкообразного масштабирования> <список позиций>[/code]

[code]#divZoom { -ms-content-zoom-snap: proximity snapList(10%, 50%, 75%, 100%, 200%, 400%); }[/code]


1.3. Пример приложения с базовой поддержкой жестов

Осталось только написать небольшое приложение, поддерживающее жесты на базовом уровне с применением инструментов, что мы рассмотрели ранее.

Создадим в Visual Studio новый проект с именем BasicGestures. Найдём на компьютере какой-либо графический файл с достаточно большим изображением и создадим его копию с именем image и расширением, соответствующим формату.

Теперь включим данный графический файл в состав проекта. Найдём в иерархическом списке панели Обозреватель решений "ветвь", представляющую проект, - она будет иметь название, совпадающее с именем проекта. Щёлкнем на ней правой кнопкой мыши и выберем в подменю Добавить появившегося на экране контекстного меню пункт Существующий элемент. (Также можно нажать комбинацию клавиш <Shift>+<Alt>+<A>.) На экране появится стандартное диалоговое окно открытия файла Windows; выберем в нём файл, что требуется добавить в проект, и нажмём кнопку Открыть.

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

Откроем файл default.html, в котором описывается интерфейс приложения, удалим весь код, что присутствует в теге <body>, и введём туда такой код:

[code]<div id="divMain">
<img id="imgMain" src="\images\image.jpg">
</div>[/code]

Здесь мы создали блок (блочный контейнер <div>), а в нём - элемент графического изображения, в котором будет выводиться изображение, которое мы только что добавили в проект. (Здесь подразумевается, что оно сохранено в формате JPEG; если оно хранится в другом формате, следует соответственно изменить расширение графического файла.)

Откроем файл default.css, в котором описывается оформление приложения, и создадим в нём стили, описанные далее.

[code]#divMain {
width: 100%;
height: 100%;
overflow: auto;
-ms-content-zooming: zoom;
}[/code]

Растягиваем блок divMain на весь экран (атрибуты стиля width и height указывают, соответственно, ширину и высоту элемента интерфейса) и задаём для него возможность прокрутки в горизонтальном и вертикальном направлениях и масштабирования содержимого.

[code]#imgMain { -ms-touch-action: manipulation; }[/code]

Даём элементу графического изображения imgMain возможность обрабатывать жесты перемещения по горизонтали и вертикали и изменения масштаба.

Логику приложения мы создавать не будем. Так что сразу же сохраним все исправленные файлы.


1.4. Имитатор Visual Studio и его использование

И запустим приложение на выполнение в имитаторе (simulator). Имитатор Visual Studio можно рассматривать как виртуальную машину, поставляемую в составе данного пакета и содержащую внутри себя полностью работоспособную копию Windows 8. Имитатор, в числе прочего, позволяет эмулировать "многопальцевые" жесты с помощью одной лишь мыши, чем мы сейчас и воспользуемся.

Указать Visual Studio, что приложение следует запускать в имитаторе, а не как обычно - непосредственно в среде Windows 8, очень просто. Найдём в панели инструментов небольшой раскрывающийся список, в котором изначально будет выбран пункт Локальный компьютер, и выберем там пункт Имитатор. Всё!

Теперь собственно запустим приложение. Вскоре на экране появится окно имитатора, в котором будет запущено наше приложение (рис. 1).



Рис. 1. Приложение BasicGestures, запущенное в имитаторе Visual Studio



Вдоль правого края окна имитатора тянется панель инструментов, кнопки которой помогут нам, в том числе, моделировать "многопальцевые" жесты. Кнопка Basic touch mode (четвёртая сверху) - она имеет вид "указующего перста" - включит режим обычного "однопальцевого" касания, который поможет нам проверить перемещение элементов интерфейса; в этом случае мы сможем перетаскивать элементы интерфейса, удерживая левую кнопку мыши. А кнопка Pinch/zoom touch mode (пятая сверху) активизирует режим масштабирования; масштабировать элементы можно, зажав левую кнопку мыши и вращая её колёсико.

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

Попытаемся изменить параметры прокрутки и масштабирования, использовав изученные ранее атрибуты стиля, и посмотрим, как эти изменения отразятся на работе приложения.

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


2. Расширенные средства для обработки жестов

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

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


2.1. Обработчик жестов

Существуют два способа обработки сложных жестов на программном уровне.

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

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

Сначала нам следует создать экземпляр объекта MSGesture. Выполняется это давно знакомым нам способом - с помощью оператора new. Конструктору при этом не требуется передавать никаких параметров.

[code]var oGesture = new MSGesture();[/code]

Далее мы присвоим свойству target полученного экземпляра объекта элемент интерфейса, который должен получать события жестов. (Эти события мы рассмотрим в следующем параграфе.)

[code]var divTarget = document.getElementById("divTarget");
oGesture.target = divTarget;[/code]

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

Здесь нам поможет метод addPointer объекта MSGesture. Он принимает в качестве единственного параметра целочисленный идентификатор касания, который можно получить из свойства pointerId объекта MSPointerEvent (подробнее - в предыдущей статье). Результата этот метод не возвращает.

[code]divTarget.addEventListener("MSPointerDown", function(evt) {
oGesture.addPointer(evt.pointerId);
});[/code]


2.2. События жестов

Теперь рассмотрим события, которые возникают в элементе интерфейса в процессе выполнения жестов.

Заметим сразу, что данный элемент интерфейса должен быть указан в свойстве target экземпляра объекта MSGesture. В противном случае он не сможет получать события жестов.

Все события жестов, что поддерживаются Windows 8, перечислены далее.

  • MSGestureTap - возникает, когда пользователь касается экрана пальцем и тотчас отпускает его, или, говоря другими словами, при обычном нажатии пальцем на элемент интерфейса. Кроме того, данное событие возникает при щелчке мышью и касании экрана или дигитайзера пером или стилусом - это сделано ради совместимости.
  • MSGestureHold - возникает, когда пользователь касается экрана пальцем и удерживает его на экране какое-то время.
  • MSGestureStart - возникает перед тем, как пользователь начнёт перемещать пальцы по экрану (то есть когда жест начинает выполняться).
  • MSGestureChange - периодически возникает в процессе перемещения пальцев по экрану (в процессе выполнения жеста).
  • MSGestureEnd - возникает после удаления всех пальцев с экрана и завершении всех "инерционных" действий (когда жест полностью выполнен).
  • MSInertiaStart - возникает перед началом "инерционных" действий.



Дадим необходимые пояснения.

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

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

Теперь рассмотрим случай, когда пользователь устанавливает пальцы на экран, быстро перемещает их и убирает. Здесь также сначала возникнет событие MSGestureStart, а за ним - серия событий MSGestureChange, продолжающаяся, пока пользователь не уберёт пальцы с экрана. Как только это случится, возникает событие MSInertiaStart, отмечающее момент снятия пальцев с экрана и начало действия "инерции". Затем снова следует серия событий MSGestureChange, обозначающих выполнение уже "инерционных" действий, а после их окончания - событие MSGestureEnd.

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


2.3. Получение сведений о событиях жестов

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

Объект этот поддерживает много полезных для нас свойств, хранящих данные о выполняемом пользователем жесте. Давайте их перечислим.

  • currentTarget - элемент интерфейса, в котором в данный момент выполняется обработка события (может не совпадать с элементом, в котором это событие изначально возникло).
  • expansion - диаметр области, в которой выполняется жест, в виде числа с плавающей точкой в пикселах.
  • gestureObject - экземпляр объекта MSGesture, обрабатывающий этот жест.
  • hwTimestamp - время возникновения события в миллисекундах в виде целого числа.
  • offsetX - горизонтальная координата точки, относительно которой выполняется масштабирование и вращение, вычисленная в системе координат элемента, принявшего событие, в виде целого числа в пикселах.
  • offsetY - вертикальная координата точки, относительно которой выполняется масштабирование и вращение, вычисленная в системе координат элемента, принявшего событие, в виде целого числа в пикселах.
  • rotation - угол поворота, отсчитываемый по часовой стрелке, в виде числа с плавающей точкой в градусах от 0 до 359.
  • scale - масштаб в виде числа с плавающей точкой.
  • target - элемент интерфейса, в котором данное событие изначально возникло.
  • translationX - смещение по горизонтали в виде числа с плавающей точкой в пикселах.
  • translationН - смещение по вертикали в виде числа с плавающей точкой в пикселах.
  • velocityAngular - угловая скорость поворота в виде числа с плавающей точкой в радианах в секунду.
  • velocityExpansion - скорость, с которой выполняется масштабирование, в виде числа с плавающей точкой.
  • velocityX - скорость движения по горизонтали в виде числа с плавающей точкой.
  • velocityY - скорость движения по вертикали в виде числа с плавающей точкой.



[code]divTarget.addEventListener("MSGestureChange", function(evt) {
var oMatrix = new MSCSSMatrix(divTarget.style.transform);
oMatrix = oMatrix.translate(evt.offsetX, evt.offsetY);
oMatrix = oMatrix.translate(evt.translationX, evt.translationY);
oMatrix = oMatrix.rotate(evt.rotation);
oMatrix = oMatrix.scale(evt.scale);
oMatrix = oMatrix.translate(-evt.offsetX, -evt.offsetY)
divTarget.style.transform = oMatrix;
});[/code]

Здесь мы выполняем смещение, поворот и масштабирование элемента интерфейса в соответствии с выполненным пользователем жестом. Для выполнения всех этих действий мы пользуемся преобразованиями CSS3.

Все объекты, представляющие элементы интерфейса, поддерживают свойство style. Оно хранит экземпляр объекта CSSStyleDeclaration, описывающий стиль, что привязан непосредственно к этому элементу (через атрибут тега style). Данный объект поддерживает множество свойств, каждое из которых соответствует определённому атрибуту стиля.

В данном случае нам понадобится свойство transform. Оно хранит экземпляр объекта MSCSSMatrix, описывающий матрицу преобразований, что уже применены к данному элементу. Матрица преобразований хранит в себе описания всех поддерживаемых CSS3 преобразований: смещения, масштабирования, поворота и сдвига.

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

Далее смещаем элемент divTarget таким образом, чтобы его левый верхний угол находился в точке, относительно которой были выполнены жесты масштабирования и вращения, - это нужно, чтобы правильно повернуть его и изменить его масштаб. Здесь нам пригодится метод translate объекта MSCSSMatrix. В качестве параметров он принимает величины горизонтального и вертикального смещения элемента, заданные в виде чисел с плавающей точкой в пикселах.

А теперь - внимание! Метод translate, как и другие методы объекта MSCSSMatrix, что мы рассмотрим далее, не изменяет матрицу преобразований, у которой был вызван. Вместо этого он возвращает изменённую матрицу в качестве результата. Не забываем об этом!

Далее смещаем элемент в ответ на жест смещения, для чего также применим метод translate.

Чтобы реализовать поворот элемента, мы применим метод rotate объекта MSCSSMatrix. Он принимает в качестве единственного параметра угол поворота, заданный в виде числа с плавающей точкой в градусах.

Для реализации масштабирования элемента нам понадобится метод scale объекта MSCSSMatrix. Единственным параметром он принимает масштаб элемента в виде числа с плавающей точки.

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

И последним выражением зададим для элемента полученную матрицу преобразований.

Как видим, обеспечить поддержку жестов на программном уровне совсем несложно.


2.4. Блокирование базовой поддержки жестов

Осталось рассмотреть ещё один важный вопрос.

Если мы собираемся обеспечить поддержку жестов программными средствами - в коде логики, то должны блокировать базовые средства, рассмотренные нами ранее. Для этого достаточно привязать к элементу, который должен поддерживать жесты, стиль, в котором для атрибута стиля -ms-touch-action указать значение none.

[code]#divTarget { -ms-touch-action: none; }[/code]


2.5. Пример приложения с поддержкой жестов на программном уровне

Давайте в качестве практического занятия создадим ещё одно приложение с поддержкой жестов. Но теперь для этого мы используем расширенные, программные средства.

Создадим в Visual Studio новый проект ComplexGestures. Опять же, найдём на компьютере графический файл, хранящий достаточно большое изображение, создадим его копию с именем image и включим его в состав проекта.

Откроем файл default.html, в котором описывается интерфейс приложения, удалим весь код, что уже есть в теге <body>, и введём туда вот что:

[code]<div id="divMain">
<img id="imgMain" src="\images\image.jpg">
</div>[/code]

Как видим, этот код ничем не отличается от того, что формирует интерфейс нашего первого приложения BasicGestures.

Откроем файл default.css, в котором описывается оформление приложения, и создадим в нём стили, описанные далее.

[code]#divMain {
width: 100%;
height: 100%;
overflow: auto;
}
#imgMain { -ms-touch-action: none; }[/code]

Здесь нечего комментировать - всё нам уже знакомо. Единственное: мы удалили из стиля, привязанного к блоку divMain, атрибут стиля -ms-content-zooming - всё равно для элементов, не реагирующих на жесты, он не имеет значения.

Переключимся на файл default.js, где описывается логика приложения. Сразу же введём код, объявляющий необходимые переменные:

[code]var imgMain, oGesture;[/code]

Напишем код инициализации:

[code]document.addEventListener("DOMContentLoaded", function() {
oGesture = new MSGesture();
imgMain = document.getElementById("imgMain");
oGesture.target = imgMain;
imgMain.addEventListener("MSPointerDown", imgMainMSPointerDown);
imgMain.addEventListener("MSGestureChange", imgMainMSGestureChange);
});[/code]

Напишем код, объявляющий обработчики событий:

[code]function imgMainMSPointerDown(evt) {
oGesture.addPointer(evt.pointerId);
};

function imgMainMSGestureChange(evt) {
var oMatrix = new MSCSSMatrix(imgMain.style.transform);
oMatrix = oMatrix.translate(evt.offsetX, evt.offsetY);
oMatrix = oMatrix.translate(evt.translationX, evt.translationY);
oMatrix = oMatrix.rotate(evt.rotation);
oMatrix = oMatrix.scale(evt.scale);
oMatrix = oMatrix.translate(-evt.offsetX, -evt.offsetY)
imgMain.style.transform = oMatrix;
};[/code]

Сохраним все исправленные файлы, запустим приложение в имитаторе и проверим, как оно работает.


3. Заключение

Вот мы и познакомились с механизмами Windows 8, позволяющими реализовать в приложениях Windows Store поддержку сложных, "многопальцевых" жестов. И убедились, что сделать это очень просто.

Справедливости ради нужно упомянуть, что существует ещё один способ сделать это - применить так называемый распознаватель жестов, объект Windows.UI.Input.GestureRecognizer. По сравнению уже знакомым нам обработчиком жестов - объектом MSGesture - он предоставляет дополнительные возможности по поддержке жестов и позволяет отслеживать жесты более тонко. Но в большинстве случаев эти дополнительные возможности излишни.

Что ж, похоже, термины "платформа Metro" и "Metro-приложение" ушли в прошлое... Отныне за поддержку приложений Windows Store "отвечает" Windows 8.


Дополнительные материалы



dronov_va, TheVista.Ru Team
Сентябрь 2012

  Передать на печать





Все права принадлежат © MSInsider.ru и TheVista.ru, 2013
Сайт является источником уникальной информации о семействе операционных систем Windows и других продуктах Microsoft. Перепечатка материалов возможна только с разрешения редакции.
Работает на WMS 1.1 (Страница создана за 0.094 секунд)