Главная » Разработка для Windows Phone 7 » Основы работы с сенсорным вводом Windows Phone 7

0

Даже для опытных разработчиков на Silverlight и XNA Windows Phone 7 предлагает возможность, которая, скорее всего, окажется новой и необычной. Экран телефона чувствителен к прикосновению и существенно отличается от старых сенсорных экранов, в основном повторяющих ввод с мыши, или экранов планшетных устройств, которые могут распознавать рукописный ввод.

Мультисенсорный экран устройства Windows Phone 7 может распознавать одновременное касание как минимум в четырех точках. Именно обработка взаимодействия этих одновременных касаний делает задачу реализации мультисенсорного ввода такой сложной для разработчиков. Но для данной главы я припас несколько менее амбициозную цель. Я просто хочу познакомить читателей с сенсорными интерфейсами в контексте примеров приложений, которые могут реагировать на простые касания.

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

Приведенные в данной главе программы во многом схожи с простыми приложениями «Hello, Windows Phone 7!» из первой главы. Единственное отличие в том, что при касании текста пальцем, он будет случайным образом менять свой цвет, а при касании вне области текста, он будет опять возвращаться к исходному белому цвету (или любому другому цвету, какой будет применен к тексту при запуске программы).

В программе на Silverlight сенсорный ввод реализован через события. В приложении на XNA сенсорный ввод передается через статический класс, опрашиваемый в ходе выполнения метода Update. Одно из основных назначений XNA-метода Update – проверка состояния сенсорного вводи и внесение изменений, которые отображаются на экране во время выполнения метода Draw.

Обработка простого касания в XNA

В XNA устройства мультисенсорного ввода называют сенсорной панелью. Для обработки такого ввода используются методы статического класса TouchPanel (Сенсорная панель). Имеется также возможность обработки жестов, но пока начнем с более простыми данными касания.

Можно (но это не является обязательным) получать сведения о самом устройстве мультисенсорного ввода через вызов статического метода TouchPanel.GetCapabilities. Объект TouchPanelCapabilities (Возможности сенсорной панели), возвращаемый этим методом, имеет два свойства:

• IsConnected (Подключен) имеет значение true, если сенсорная панель доступна. Для телефона его значение всегда true.

•         MaximumTouchCount (Максимальное число касаний) возвращает количество точек касания, как минимум 4 для телефона.

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

TouchCollection touchLocations = TouchPanel.GetState();

TouchCollection (Коллекция касаний) – это коллекция, включающая нуль или более объектов TouchLocation (Место касания). TouchLocation имеет три свойства:

•         State (Состояние), его значениями являются элементы перечисления TouchLocationState (Состояние места касания): Pressed (Нажат), Moved (Перемещен), Released (Высвобожден).

•         Position (Местоположение) – это Vector2, обозначающий положение пальца относительно верхнего левого угла окна просмотра.

•         Id – целое число, идентифицирующее отдельное касание от состояния Pressed до Released, то есть в течение всего времени касания.

Если ни один палец не касается экрана, коллекция TouchCollection пуста. Когда палец впервые касается экрана, в TouchCollection появляется объект, свойство State которого имеет значение Pressed. Последующие вызовы TouchPanel.GetState покажут, что значение State объекта TouchLocation равно Moved, даже если фактически палец никуда не перемещался. Когда палец будет убран с экрана, свойство State объекта TouchLocation примет значение Released. Последующие вызовы TouchPanel.GetState продемонстрируют, что коллекция TouchCollection опять пуста.

Единственное исключение, если палец быстро «постукивает» по экрану – т.е. поднимается и опускается на экран с частотой примерно 1/30 секунды – свойство State объекта TouchLocation от значения Pressed сразу перейдет к значению Released, минуя состояния Moved.

Я описал касание всего одним пальцем. Как правило, экрана будут касаться множество пальцев; и опускаться, перемещаться и покидать экран они будут независимо друг от друга. Для отслеживания отдельного касания используется свойство Id (Идентификатор). Для одного отдельно взятого касания Id будет неизменным от состояния Pressed, на протяжении всех перемещений (значения Moved) и до состояния Released.

Части при работе с простым касанием используется объект Dictionary (Словарь) с ключами, созданными на основании свойства Id, для извлечения данных конкретного касания.

TouchLocation также имеет очень удобный метод TryGetPreviousLocation (Попытаться получить предыдущее местоположение), который вызывается следующим образом:

TouchLocation previousTouchLocation;

bool success = touchLocation.TryGetPreviousLocation(out previousTouchLocation);

Вызов этого метода практически всегда происходит, когда touchLocation.State имеет значение Moved, для получения предыдущего местоположения и вычисления разницы. Если значение touchLocation.State равно Pressed, TryGetPreviousLocation возвратит false, и значением previousTouchLocation.State будет элемент перечисления TouchLocationState.Invalid. Такие же результаты будут получены в случае вызова этого метода для TouchLocation, который был возвращен TryGetPreviousLocation.

Предлагаемое здесь мною приложение меняет цвет текста при касании пользователем экрана, т.е. обработка TouchPanel.GetStates будет относительно простой. Логика приложения

будет проверять только объекты TouchLocation, значение свойства State которых равно Pressed.

Назовем этот проект XnaTouchHello. Как и во всех рассматриваемых до этого проектах на XNA, нам понадобится шрифт, который я немного увеличил, чтобы обеспечить более удобную для касания мишень. Потребуется еще несколько дополнительных полей:

Проект XNA: XnaTouchHello Файл: Game1.cs (фрагмент, демонстрирующий поля)

public class Game1 : Microsoft.Xna.Framework.Game {

GraphicsDeviceManager graphics; SpriteBatch spriteBatch;

Random rand = new Random();

string text = "Hello, Windows Phone 7!";

SpriteFont segoe36;

Vector2 textSize;

Vector2 textPosition;

Color textColor = Color.White;

Метод LoadContent аналогичен используемому ранее, за исключением того, что textSize сохраняется как поле. Это обеспечит возможности доступа к нему при последующих вычислениях:

Проект XNA: XnaTouchHello Файл: Game1.cs (фрагмент)

protected override void LoadContent() {

spriteBatch = new SpriteBatch(GraphicsDevice);

segoe36 = this.Content.Load<SpriteFont>("Segoe3 6"); textSize = segoe3 6.MeasureString(text); Viewport viewport = this.GraphicsDevice.Viewport; textPosition = new Vector2((viewport.Width – textSize.X) / 2,

(viewport.Height – textSize.Y) / 2);

}

Как это свойственно приложениям на XNA, «действие» происходит преимущественно в методе Update. Этот метод вызывает TouchPanel.GetStates и затем поэлементно обходит коллекцию объектов TouchLocation, выбирая те из них, значение State которых равно Pressed.

Проект XNA: XnaTouchHello Файл: Game1.cs (фрагмент)

protected override void Update(GameTime gameTime) {

if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this .Exit();

TouchCollection touchLocations = TouchPanel.GetState();

foreach (TouchLocation touchLocation in touchLocations) {

if (touchLocation.State == TouchLocationState.Pressed) {

Vector2 touchPosition = touchLocation.Position;

if (touchPosition.X >= textPosition.X &&

touchPosition.X < textPosition.X + textSize.X && touchPosition.Y >= textPosition.Y && touchPosition.Y < textPosition.Y + textSize.Y)

{

textColor = new Color((byte)rand.Next(25 6), (byte)rand.Next(256), (byte)rand.Next(25 6));

}

else {

textColor = Color.White;

}

}

}

base.Update(gameTime);

}

Если Position оказывается где-нибудь внутри области, занимаемой текстовой строкой, полю textColor (Цвет текста) присваивается случайное значение RGB для цвета с помощью одного из конструкторов структуры Color (Цвет). В противном случае textColor присваивается значение Color.White.

Метод Draw практически аналогичен используемому в предыдущих примерах, только цвет текста теперь стал переменным:

Проект XNA: XnaTouchHello Файл: Game1.cs (фрагмент)

protected override void Draw(GameTime gameTime) {

this.GraphicsDevice.Clear(Color.Navy); spriteBatch.Begin();

spriteBatch.DrawString(segoe3 6, text, textPosition, textColor); spriteBatch.End();

base.Draw(gameTime);

}

Единственная проблема в том, что касание не так строго детерминировано, как этого хотелось бы. Даже при касании одним пальцем контактов с экраном может быть несколько. В некоторых случаях один и тот же цикл foreach в методе Update может задавать textColor несколько раз!

Источник: Чарльз Петзольд, Программируем Windows Phone 7, Microsoft Press, © 2011.

По теме:

  • Комментарии