Обработка касания экрана андроид студио
Мы уже поработали в предыдущем уроке с акселерометром смартфона и сделали программу, способную распознавать движение аппарата в пространстве. В этом уроке мы поработаем над возможностями сенсорного экрана, научимся работать с жестами по дисплею, то есть, как научить наше приложения работать с прикосновениями пальцев пользователя, при чем эти прикосновения не будут направлены на какой нибудь элемент управления (кнопка, переключатель и т.д.).
Начинаем с создания проекта. Названия оставим по умолчанию, но, конечно, можете написать что то свое.
Сразу начнем с работы в основном layout файле activity_main.xml. Добавим туда следующие элементы:
Важным моментом здесь является определение элемента FrameLayout. Именно в нем будет происходить основная работа приложения.
Теперь перейдем к файлу MainActivity.java и немного изменим метод onCreate:
Мы объявили здесь класс под названием PlayAreaView и Android Studio на него ругается, но не пугайтесь, мы это исправим.
А сейчас мы выполним довольно интересную часть нашей работы — создадим холст для рисования жестов. Легкий способ это сделать заключается в том, чтобы создать объект для рисования Canvas (холст) с помощью метода onDraw. Это довольно просто и удобно, так как этот метод имеет всего один параметр: объект Canvas. Рисование в Canvas происходит с помощью вызова метода drawBitmap. Создаем в приложении новый класс по имени PlayAreaView.java и добавляем туда следующий код:
В нашем случае выполнение метода onDraw довольно простое. Как это обычно делается, определите еще и переменную DEBUG_TAG. Основная работа в этой части кода происходит при вызове команды drawBitmap, где первым параметром является изображение для рисования, второй параметр задает матричный объект под названием translate, который, как подсказывает его имя, будет показывать, где именно на экране будет происходить рисование. Этот матричный объект будет связывать все действия пользователя, все его прикосновения к экрану, с холстом.
Классу PlayAreaView нужно создать конструктор, выполняющий его самые базовые, начальные настройки. Так, как приложения будет реагировать на жесты, нам необходимо задать GestureDetector (определитель жестов). GestureDetector это класс, способный опознавать события типа жестов (прикасания пользователя к дисплею), проделывать над полученной от датчиков информацией о жестах математические операции, а потом, с помощью объекта GestureListener, создавать определенную обратную реакцию. О бъект GestureListener обрабатывает входящую в него информацию и выдает ответ, который мы можем видеть и реагировать не него (в нашем случае это будет перемещение изображения по экрану). В GestureDetector существует множество возможностей, но мы ограничимся только самыми необходимыми. Добавим этот метод в код файла PlayAreaView.java:
Взглянем на код немного пристальнее. Сначала мы инициализируем необходимый объект матрицы, который будет помогать нам в рисовании, и оно будет происходить в местах, определенных по умолчанию. Далее мы создаем объект GestureDetector и задаем GestureListener. Ну и напоследок, загружаем стандартную картинку, с которой будем работать в приложении. Вы можете использовать там любое изображение по собственному желанию. Это будет изображение, которое мы с помощью жестов будем заставлять перемещаться по рабочему холсту.
Теперь давайте создадим объект GestureDector, который будет принимать данные о жестах и обрабатывать их. Для этого в том же классе PlayAreaView.java добавим следующее:
В процессе работы с определением жестов с помощью GestureDector также нужно реализовать класс GestureListener. Основные жесты, в которых мы заинтересованы, это двойное нажатие по экрану и направленные движения (влево, вправо и т.д.). Для реализации определения этих движений, класс GestureListener должен выполнять интерфейсы OnGestureListener и OnDoubleTapListener:
После добавления этого класса, как подкласса Activity, добавьте все необходимые для них методы, которых жаждет Android Studio. Например, вот один из них:
Выполнение всех этих методов позволит вам изучить самые различные события, которые улавливает объект GestureDetector. Объект MotionEvent связан с самыми разными событиями, которые могут происходить при нажатии пользователем на экран.
Стоит отметить, что существует еще такой удобный метод, как SimpleOnGestureListener, который объединяет в себе функционал сразу двух интерфейсов: OnGestureListener и OnDoubleTapListener. В нем по умолчанию возвращается значение false.
Первое движение, с которым мы хотим работать в нашем приложении, это прокрутка. Оно происходит тогда, когда пользователь прикасается к экрану и, не отрывая пальца, ведет им в какую либо сторону. Это движение мы можем определить в интерфейсе OnGestureListener с помощью метода onScroll:
Выполнение этого метода является важным в связи с событием, когда пользователь ведет по экрану пальцем и вместе с этим начинает двигаться изображение на дисплее.
Изображение будет двигаться вдоль всего экрана, а иногда даже выходить за его границы. По определению, изображение будет видимым только тогда, когда его координаты находятся в рамках объекта для рисования (а его рамки у нас совпадают с размерами рабочего окна приложения), если же затащить изображение за эти границы, то оно будет не видимым. Также мы реализуем метод, который по двойному клику будет возвращать на экран заблудшее за рамками экрана изображение:
В принципе, в этом методе мы просто сбрасываем положение картинки на ее положение по умолчанию.
Следующее движение, которое мы будем определять и использовать, можно назвать инерцией. То есть, мы резким движением как бы толкаем картинку в определенную сторону, убираем палец, а она летит по инерции в указанном направлении, постепенно замедляя скорость до полной остановки. Скорость затухания этого движения задается программистом. Например, почти в каждой игре, где есть движение, есть своя физика процесса в которую входит и эта настройка в том числе. Самая лучшая настройка этого параметра может появиться только благодаря экспериментам и качественному подбору, либо же наугад что мы и сделаем.
В нашем случае, мы будем изменять время разности между событием, спровоцировавшим движение, и остановкой инерциального движения, а потом просто запускать анимацию движения картинки к нужному месту с нужной скоростью. Для этого будет использоваться метод onFling. Задание кажется довольно сложным, но я не дам вам шанса над ним подумать и покажу готовый код:) :
Нам даже не нужно выполнять никаких дополнительных проверок параметров, данные о скорости полностью решают нашу задачу. Скорость будет определяться в пискелях за секунду. Мы также можем использовать данные скорости для решения вопроса о том, где остановить движущийся объект, которым у нас является картинка. В нашем случае, мы используем в своих подсчетах 40% от секунды (то есть 400 мс). Данные о скорости будут передаваться в метод onAnimateMove, где и будет задаваться скорость движения изображения. Почему используется именно 400 мс? Потому, что это значение параметра наиболее качественно подходит к большинству устройств. Используя такое значение, мы будем видеть нормальное, относительно плавное движение, а не скачки или некрасивые замедления. Стоит отметить, что эти настройки скорости и анимации не имеют ничего общего с реальной физикой, просто в данном примере так удобно.
Теперь все жесты, которые нам были интересны, учтены. В методе PlayAreaView.java добавим такой метод:
Он делает две вещи. Во первых, метод переводит (здесь «переводит» означает движение от точки A в B) изображение на расстояние в соответствии с движением пальца, во вторых, аннулирует предыдущее положение изображения. Каждый раз, когда происходит движение, мы будем просто обновлять нашу матрицу, заданную ранее.
Теперь добавим onResetLocation метод:
Этот метод будет просто сбрасывать все настройки на настройки по умолчанию.
При движении картинки в заданном пальцем пользователя направлении нужно настроить анимацию так, чтобы она была плавной, проходила гладко, так сказать. В Android есть встроенные классы для анимации (вспоминаем предыдущие уроки по анимации, вот, вот и вот) но в нашем случае их сложно применить. Создадим для приложения свою собственную анимацию. В Android существуют множество интерполяторов, с помощью которых можно задать различную анимацию. Вот их мы и применим для создания анимации. Давайте создадим метод под названием onAnimateMove :
Здесь мы задали начальное положение, начальное и конечное время. Мы инициализируем анимацию, используя класс OvershootInterpolator, и настраиваем ее основные характеристики. Напоследок для завершения работы над анимацией нужно вызвать еще один метод под названием onAnimateStep:
Вот, в принципе, и все основные шаги, которые нужно выполнить для создания программы, способной распознавать жесты пользователя и реагировать на них. Конечно, руководство далеко от идеала, но здесь можно почерпнуть много интересного и познавательного материала, что поможет немного разобраться в использовании подобных инструментов. Удачи в обучении!
Источник
Обработка касания экрана андроид студио
Объект класса MotionEvent используется для сообщения о событиях перемещения (мыши, пера, пальца, трекбола). Motion events (события перемещения) могут содержать либо абсолютные, либо относительные перемещения и другие данные, в зависимости от типа устройства.
[Обзор класса MotionEvent]
События перемещения описывают перемещения в виде кода действий (action code) и набора значений осей координат. Action code указывает изменение состояния, которое происходит, когда указатель опускается или поднимается. Значения координат осей описывают позицию и другие свойства перемещения.
Например, когда пользователь первый раз касается экрана, система передает событие касания (touch event) к соответствующему элементу визуального интерфейса View с кодом действия ACTION_DOWN (это и есть action code), с набором координат X и Y точки касания, и с информацией о давлении, размере и ориентации области касания.
Некоторые устройства могут сообщать о сразу нескольких путях перемещения, происходящих одновременно. Экраны с поддержкой мультитача (Multi-touch screens, экраны с определением множественных касаний) выдает трассу перемещения для каждого пальца. Отдельные пальцы или другие объекты, которые генерируют трассы перемещения, называются указателями (pointers). События перемещения содержат информацию о всех указателях, которые активны в настоящий момент, даже если некоторые из них не переместились с момента последнего полученного события.
Количество указателей всегда изменяется только на 1, когда отдельные указатели опускаются и поднимаются, за исключением случая отмены жеста.
Каждый указатель имеет уникальный идентификатор, который назначается при первом опускании (показывается кодом ACTION_DOWN или ACTION_POINTER_DOWN ). Идентификатор указателя остается валидными, пока указатель не поднимется (показывается кодом ACTION_UP или ACTION_POINTER_UP ), или когда жест отменен (показывается кодом ACTION_CANCEL ).
Класс MotionEvent предоставляет несколько методов для опроса позиции и других свойств указателей, такие как getX(int) , getY(int) , getAxisValue(int) , getPointerId(int) , getToolType(int) и многие другие. Большинство этих методов принимают индекс указателя в качестве параметра, а не идентификатор указателя. Индекс каждого указателя находится в диапазоне от 0 до getPointerCount() -1.
Заранее не определен порядок, в котором указатели появляются в событии перемещения. Таким образом индекс одного и того же указателя может поменяться от одного события к другому, но идентификатор указателя гарантированно останется неизменным, пока указатель остается активным. Используйте метод getPointerId(int), чтобы получить идентификатор указателя, и отслеживать его через последующие события перемещения в жесте. Тогда для последовательных событий перемещения используйте метод findPointerIndex(int), чтобы получить индекс указателя на предоставленный идентификатор указателя в этом событии перемещения.
Мышь и кнопки стилуса могут быть получены с использованием getButtonState() . Хорошая идея проверить состояние кнопки при обработки ACTION_DOWN как части события касания. Приложение может выполнять разные действия при появлении события касания, если событие касания сопровождается вторым нажатием на кнопку, как например вызов контекстного меню.
[Пакетная обработка (Batching)]
Для эффективности события перемещения с ACTION_MOVE могут группировать вместе несколько выборок перемещения в один объект (batch). Самые актуальные текущие координаты доступны через вызов getX(int) и getY(int). Предыдущие координаты в batch доступны через getHistoricalX(int, int) и getHistoricalY(int, int). Координаты будут «историческими» (historical) только потому, что они старше текущих координат в batch; однако они все равно более актуальные, чем другие координаты, которые были получены в других событиях перемещения. Чтобы обработать все координаты в batch с привязкой по времени, сначала рассмотрите historical-координаты и затем текущие координаты.
Пример, получение всех выборок для всех указателей в порядке по времени:
[Типы устройств]
Интерпретация содержимого MotionEvent значительно варьируется в зависимости от источника класса устройства.
Для устройств указания с исходным классом SOURCE_CLASS_POINTER , таких как тачскрины, координаты указателя показывают абсолютные позиции, такие как координаты X/Y представления. Каждый полный жест представлен последовательностью событий перемещения с действиями, которые описывают переходы состояний указателя и перемещения. Жест начинается с события перемещения ACTION_DOWN, которое предоставляет место первого опускания указателя. Для каждого дополнительного указателя, который опускается вниз или вверх, фреймворк будет генерировать событие перемещения с ACTION_POINTER_DOWN или ACTION_POINTER_UP соответственно. Перемещения указателя описаны в событиях перемещения с ACTION_MOVE. Окончание жеста происходит либо когда поднимается последний указатель (по событию перемещения с ACTION_UP), или когда жест отменен (с событием перемещения ACTION_CANCEL).
Некоторые устройства указания, такие как мыши, могут поддерживать вертикальную и/или горизонтальную прокрутку (scrolling). Событие прокрутки сообщается как обычное событие перемещений с ACTION_SCROLL , которое включает в себя смещение прокрутки в по осям AXIS_VSCROLL и AXIS_HSCROLL . См. описание getAxisValue(int) для дополнительной информации как получать эти дополнительные оси.
Устройства трекбол с исходным классом SOURCE_CLASS_TRACKBALL получают координаты указателя, которые задают относительное перемещение (изменение) по осям X/Y. Жест трекбола состоит из последовательности перемещений, описанных событиями перемещения с ACTION_MOVE, перемежающимися со случающимися событиями ACTION_DOWN или ACTION_UP, когда кнопки трекбола нажимаются или отпускаются.
Устройства джойстика с исходным классом SOURCE_CLASS_JOYSTICK , получают координаты указателя с абсолютной позицией по осям джойстика. Значения осей джойстика нормализуются к диапазону от -1.0 до 1.0, где 0.0 соответствует центральному положению. Больше информации по набору доступных осей и диапазону перемещений можно получить через getMotionRange(int). Общие оси джойстика: AXIS_X, AXIS_Y, AXIS_HAT_X, AXIS_HAT_Y, AXIS_Z и AXIS_RZ.
Обратитесь к InputDevice для дополнительной информации о различных видах устройств ввода, источниках, предоставляющих координаты указателя.
[Гарантии согласованности]
События перемещения всегда передаются в представления (view) как последовательный поток событий. Что из себя представляет последовательный поток — зависит от типа устройства. Для событий касания последовательность включает в себя информацию по опусканию указателей с привязкой ко времени, групповым перемещением, и затем с поднятием по одному или с отменой жеста.
Хотя фреймворк пытается передать непрерывный поток событий перемещения к элементам интерфейса (View), нет полной гарантии о передаче всех событий. Некоторые события могут быть отброшены или модифицированы элементами интерфейса в приложении до того, как будут доставлены, в результате чего поток событий будет неполным. Элементы интерфейса (View) должны быть всегда готовы к обработке ACTION_CANCEL и должны быть толерантны к аномальным ситуациям, таким как прием нового ACTION_DOWN без предварительного получения ACTION_UP для предыдущего жеста.
Полное описание констант и методов класса см. в [1].
[Пример: определение места касания экрана]
Для того, чтобы определить место касания экрана в программе Android, переопределите метод onTouchEvent для в классе Activity:
[Пример: определение места касания на виджете ImageView]
MotionEvent может использоваться для определения мест касания на изображении, чтобы по ним предпринимать различные действия. Простой пример — двухпозиционный выключатель, на левой картинке он в положении «OFF» (выключено), а на правой в положении «ON» (включено).
Идея состоит в следующем: при нажатии на верхнюю часть картинки выключатель должен «включаться» (т. е. должна показываться картинка, где выключатель в положении ON), а когда нажатие происходит на нижнюю часть картинки, то выключатель должен «выключаться» (должна показываться картинка, где выключатель в положении OFF). Далее процесс по шагам.
1. Создайте 2 картинки для состояний выключателя ON и OFF в виде файлов формата PNG, назовите эти файлы switch_on.png и switch_off.png соответственно. Положите их в папку res\drawable\ проекта. Сделайте Clean для проекта, чтобы в файле R.java сгенерировались идентификаторы для картинок.
2. Бросьте на форму программы виджет ImageView, дайте ему понятный идентификатор, например imageSwitch. В качестве источника картинки для ImageView укажите ресурс switch_off (это наша картинка для выключенного состояния выключателя). В результате в файле activity_main.xml появится определение наподобие следующего:
3. В обработчике в класс Activity программы добавьте переменную ImageView, и в обработчике onCreate сделайте инициализацию этой переменной, привязав её к добавленному виджету imageSwitch. Добавьте также для этой переменной обработчик события OnTouchListener. Вот полный код для onCreate активности:
Источник