T.M. SoftStudio

feci quod potui, faciant meliora potentes

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

Программирование мобильных приложений для платформы Android

Лекция 15

События сенсорного экрана. Часть 1

Если вы используете приложения, которые отображают карты или веб-страницы, тогда вы, вероятно, используете жесты для прокрутки представления.

Или большой палец и указательный палец, чтобы увеличить или уменьшить масштаб.

В этом уроке я начну с обсуждения событий MotionEvent.

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

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

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

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

Индивидуальное событие движения содержит несколько частей информации.

Оно имеет код действия, который указывает тип движения, которое произошло.

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

И в случае необходимости, как сильно устройство было нажато, и многое другое.

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

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

Многие устройства с сенсорным экраном сегодня являются мультитач устройствами.

Это означает, что они могут регистрировать и отслеживать одновременно несколько касаний.

В Android, мультитач устройства генерируют один трейсер (отслеживание) движения от каждого сенсорного источника.

И на каждый из этих сенсорных источников события движения ссылаются как на указатель.

Когда Android встречает новый указатель, он генерирует уникальный идентификатор, который остается константой до тех пор, пока этот указатель является активным.

В некоторых случаях, Android группирует несколько указателей в пределах одного события движения.

И в этом случае каждый указатель в событии движения может быть доступен с помощью его индекса, но знайте, что этот индекс это не то же самое, что и ID указателя.

ID указателя является константой до тех пор, пока указатель активен.

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

Итак, давайте поговорим о событиях движения более подробно.

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

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

Действие вниз, которое свидетельствует о том, что первый палец начал прикосновение к экрану.

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

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

Action_move означает, что некоторые из пальцев, которые касаются экрана, изменили свое положение.

Action_up означает, что последний из пальцев, который касался экрана, теперь остановился, прикасаясь к нему.

И Action_cancel означает, что текущий жест был преждевременно отменен.

В то время как жест происходит, Android стремится к тому, чтобы его события движения соблюдали следующие правила.

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

Если вам нужно обрабатывать события движения, Вы можете использовать некоторые из следующих методов:

Метод getActionMasked, который возвращает код действия, связанного с событием движения.

Метод getActionIndex, который возвращает индекс указателя, связанного с этим кодом действия.

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

Метод getPointerId, этот метод возвращает стабильный идентификатор указателя, связанный с этим индексом.

Метод getPointerCount, который возвращает количество указателей, связанных с событием движения.

Методы getX и getY, которые возвращают х и у координаты указателя, хранящиеся в текущем индексе.

И функция findPointerIndex, которая возвращает индекс, связанный с данным ID указателя.

Когда прикосновение происходит на View-представлении, Android генерирует событие движения, а затем пытается доставить это событие различным объектам, один из которых это само View-представление.

Android доставляет событие движения с помощью метода onTouchEvent

Этот метод может обрабатывать событие движения и должен завершаться возвращением true, если событие движения было принято, и false, если оно не было принято объектом.

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

И, регистрируя объект методом View.setOnTouchListener.

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

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

И опять же, метод onTouch должен вернуть true, если он обработал событие движения или false, если это не так.

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

Но приложения часто требуют обрабатывать сразу несколько прикосновений, которые являются частью более сложного жеста.

Для этого коду необходимо будет определить и обработать конкретную комбинацию прикосновений.

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

Все в быстрой последовательности.

Приведем несколько примеров, предположим, что вы начинаете жест, помещая один палец вниз на экран.

Это сгенерирует событие действия вниз.

И можно назначить идентификатор указателя 0 для этого указателя.

Если вы держите этот палец внизу и перемещаете его на экране, при этом вы можете получить несколько событий движения, связанных с ID=0 указателя.

Предположим теперь, что вы положили второй палец вниз.

В этом случае, вы получите action_pointer_down событие.

И это новый указатель может получить ID=1.

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

И если вы поднимите сначала первый палец, то вы получите событие действия action_pointer_up, связанное с нулевым указателем.

И потом, если вы, наконец, поднимите последний палец, вы получите событие действия action_pointer_up, связанное с указателем ID=1.

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

В этом случае мы получаем action_pointer_up событие, связанное с указателем ID=1, и, наконец, когда мы поднимаем первый палец, мы получаем action_pointer_up событие, связанное с указателем ID=0.

И для нашего последнего примера мы будем использовать три пальца.

Мы положим первый палец, затем второй, а затем третий.

И тогда мы будем двигать пальцами, и поднимать их вверх.

Во-первых, поднимая второй палец, затем первый палец и затем, наконец, поднимая третий палец.

Наш первый пример приложения называется TouchIndicateTouchLocation.

Это приложение рисует круг там, где пользователь прикасается к экрану.

Цвет круга выбирается случайным образом.

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

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

Давайте взглянем на это приложение в действии.

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

Откроем основную активность.

И этот код сначала создает пул пользовательских представлений, называемых MarkerView.

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

Далее, код определяет набор, который содержит представления MarkerView, в настоящее время отображающиеся на дисплее.

Далее в методе оnCreate, код получает компоновку, представляющую основное View-представление этой активности.

И тогда он создает слушателя прикосновений и устанавливает его в качестве получателя обратных вызовов при прикосновениях.

Когда пользователь прикасается к экрану, метод onTouch слушателя вызывается.

Этот метод начинается с проверки кода действия для нового события движения.

Если код действия показывает действие вниз action_down, или action_pointer_down, тогда произошло новое прикосновение.

Так что код создает и отображает новое представление MarkerView.

И код делает это, записывая ID указателя и индекс указателя этого события.

Затем код принимает MarkerView из неактивного списка и добавляет представление в активный набор, используя ID указателя в качестве ключа для этого представления.

Далее, код устанавливает место для этого представления, а затем обновляет общее количество касаний для каждого в настоящее время видимого MarkerView.

А потом код добавляет MarkerView в главное представление активности.

Теперь, если код действия action_up или action_pointer_up, что означает, что палец был поднят с экрана.



Здесь код по существу отменяет то, о чем мы только что закончили говорить.

Здесь, как и раньше, код начинается с записи ID указателя и индекса указателя для этого события.

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

Затем код добавляет MarkerView назад в неактивный список, и затем код обновляет общее количество прикосновений для каждого в настоящее время видимого MarkerView.

А потом код удаляет MarkerView из главного представления активности.

И, наконец, если код действия это action_moved, тогда код регулирует расположение задействованных MarkerView и инициирует их перерисовку.

Код делает это в цикле по указателям в событии движения.

Для каждого из них он получает MarkerView для данного указателя, а затем проверяет, сдвинулся ли указатель на некоторое минимальное расстояние.

Если это так, код устанавливает новое место для MarkerView.

И затем вызывает аннулирование MarkerView, что означает, что MarkerView хочет, чтобы его перерисовали.

События сенсорного экрана. Часть 2

Android предоставляет класс GestureDetector, который приложения могут использовать для распознавания общих жестов.

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

Чтобы использовать GestureDetector, вашей активности придется создать экземпляр класса GestureDetector, передавая объект, который реализует GestureDetector.OnGestureListener интерфейс.

И далее активности будет нужно переопределить свой метод onTouchEvent, который вызывается, когда активность получает сенсорное событие.

И этот метод будет потом делегировать события движения методу onTouchEvent детектора жестов.

Давайте посмотрим на пример приложения, который использует GestureDetector для распознавания жеста перелистывания.

Это приложение называется TouchGestureViewFlipper и когда оно начинается, оно представляет TextView, который отображает номер.

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

Давайте посмотрим это приложение в действии.

И обратите внимание, что этот жест перелистывания только работает, если я делаю его справа налево.

Если я попытаюсь сделать его в другом направлении, ничего не произойдет.

Давайте посмотрим на исходный код для этого приложения.

Откроем основную активность.

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

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

Так, в оnCreate, вы можете увидеть, что код создает новый GestureDetector.

И в конструкторе этого объекта, код передает новый SimpleOnGestureListener.

И этот объект определяет метод onFling.

Когда GestureDetector обнаруживает жест перелистывания, вызывается этот метод.

Давайте посмотрим на onTouchEvent метод для этой активности.

Этот метод вызывается, когда происходит событие касания.

Когда этот метод вызывается, он просто делегирует вызов GestureDetector.

Если GestureDetector в конечном итоге решает, что он встретил полный жест перелистывания, вызывается метод onFling.

И этот метод onFling получает параметр с именем velocityX, который говорит как быстро и в каком направлении жест перелистывания был выполнен.

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

Если скорость не соответствует критерию, например, если медленно перетаскивать вместо взмаха, или если жест идет в неправильном направлении, слева направо, а не справа налево, тогда жест игнорируется.

Для распознавания более сложных жестов, вы можете использовать Android приложение GestureBuilder для создания и сохранения пользовательских жестов.

Это приложение поставляется в комплекте с SDK.

Во время выполнения своего приложения вы можете использовать класс GestureLibraries для загрузки пользовательских жестов и распознавания, когда пользователь выполняет один из этих жестов.

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

И потом, оно вызывает код приложения для обработки этих жестов.

Вот скриншот приложения GestureBuilder.

Как вы видите, я создал четыре пользовательских жеста.

Горизонтальный жест слева направо, жест «нет» в виде загогулины, горизонтальный жест справа налево и жест «да», который выглядит как галочка.

На эмуляторе, GestureBuilder сохраняет ваши пользовательские жесты в файл /mnt/sdcard/gestures.

Чтобы использовать эти жесты, вы должны скопировать этот файл в каталог res/raw вашего приложения.

Давайте посмотрим на приложение TouchGestures.

Это приложение отображает маленькое представление с цветом для фона приложения.

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

Например, если пользователь выполняет жест Далее, цвет фона будет перелистываться вперед.

Если пользователь выполняет жест Предыдущий, цвет фона будет перелистываться назад.

Если пользователь выполняет жест Да, приложение устанавливает этот цвет в качестве фона приложения.

И если пользователь выполняет жест Нет, фон приложения изменяется на серый цвет.

Давайте посмотрим работающее приложение.

Давайте посмотрим на исходный код для этого приложения.

Откроем основную активность.

И вы заметите, что эта активность реализует OnGesturePerformedListener интерфейс, что означает, что он обеспечивает onGesturePerformed метод.

В методе оnCreate, код получает ссылку на макет кадра, которую он сохраняет в переменной mFrame, и это там, где появляются цвета фона.

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

Теперь, код читает файл жестов из каталога res/raw, используя метод fromRawResource класса GestureLibraries.

Этот метод возвращает объект GestureLibrary и код затем вызывает метод load для GestureLibrary.

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

Когда GestureOverlayView обнаруживает жест, он вызывает метод onGesturePerformed, показанный здесь.

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

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

Например, если жест был ДА жестом, код устанавливает фон макета как текущий цвет представления.