- Полный список
- Русские Блоги
- Подробное объяснение механизма распределения событий Android touch
- предисловие
- Сенсорные методы, связанные с событиями
- 1、dispatchTouchEvent
- 2、onInterceptTouchEvent
- 3、requestDisallowInterceptTouchEvent
- 4、onTouch
- 5、onTouchEvent
- 6、onClick
- onTouch, onTouchEvent, последовательность выполнения onClick
- Сенсорная последовательность доставки событий
- Понимание о ACTION_DOWN
- Понимание о onInterceptTouchEvent
- О появлении ACTION_CANCEL
- в конце концов
Полный список
Раньше мы для View-компонентов использовали OnClickListener и ловили короткие нажатия. Теперь попробуем ловить касания и перемещения пальца по компоненту. Они состоят из трех типов событий:
— нажатие (палец прикоснулся к экрану)
— движение (палец движется по экрану)
— отпускание (палец оторвался от экрана)
Все эти события мы сможем ловить в обработчике OnTouchListener, который присвоим для View-компонента. Этот обработчик дает нам объект MotionEvent, из которого мы извлекаем тип события и координаты.
На этом уроке рассмотрим только одиночные касания. А мультитач – на следующем уроке.
Project name: P1021_Touch
Build Target: Android 2.3.3
Application name: Touch
Package name: ru.startandroid.develop.p1021touch
Create Activity: MainActivity
strings.xml и main.xml нам не понадобятся, их не трогаем.
MainActivity реализует интерфейс OnTouchListener для того, чтобы выступить обработчиком касаний.
В onCreate мы создаем новый TextView, сообщаем ему, что обработчиком касаний будет Activity, и помещаем на экран.
Интерфейс OnTouchListener предполагает, что Activity реализует его метод onTouch. На вход методу идет View для которого было событие касания и объект MotionEvent с информацией о событии.
Методы getX и getY дают нам X и Y координаты касания. Метод getAction дает тип события касания:
ACTION_DOWN – нажатие
ACTION_MOVE – движение
ACTION_UP – отпускание
ACTION_CANCEL – практически никогда не случается. Насколько я понял, возникает в случае каких-либо внутренних сбоев, и следует трактовать это как ACTION_UP.
В случае ACTION_DOWN мы пишем в sDown координаты нажатия.
В случае ACTION_MOVE пишем в sMove координаты точки текущего положения пальца. Если мы будем перемещать палец по экрану – этот текст будет постоянно меняться.
В случае ACTION_UP или ACTION_CANCEL пишем в sUp координаты точки, в которой отпустили палец.
Все это в конце события выводим в TextView. И возвращаем true – мы сами обработали событие.
Теперь мы будем водить пальцем по экрану (курсором по эмулятору) в приложении, и на экране увидим координаты начала движения, текущие координаты и координаты окончания движения.
Все сохраним и запустим приложение.
Ставим палец (курсор) на экран
Если вчерашний вечер не удался, голова не болит, рука тверда и не дрожит :), то появились координаты нажатия.
Если же рука дрогнула, то появится еще и координаты перемещения.
Продолжаем перемещать палец и видим, как меняются координаты Move.
Теперь отрываем палец от экрана и видим координаты точки, в которой это произошло
В целом все несложно. При мультитаче процесс немного усложнится, там уже будем отслеживать до 10 касаний.
Если вы уже знакомы с техникой рисования в Android, то вполне можете создать приложение выводящее на экран геометрическую фигуру, которую можно пальцем перемещать. Простейший пример реализации можно посмотреть тут: http://forum.startandroid.ru/viewtopic.php?f=28&t=535.
На следующем уроке:
— обрабатываем множественные касания
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник
Русские Блоги
Подробное объяснение механизма распределения событий Android touch
* Эта статья авторизовала публичный аккаунт WeChat guolin_blog (郭 霖) для эксклюзивного выпуска.
предисловие
Механизм распределения событий касания всегда был относительно важной частью Android. Пользовательские представления и различные сложные взаимодействия жестов тесно связаны с механизмом распределения событий касания. Чтобы сделать это хорошо, вы должны понимать события касания. Тщательно и нужно продолжать практиковаться, чтобы углубить впечатление, в противном случае вы будете в растерянности, когда добьетесь его. В то же время этот пункт знаний также является классическим вопросом, который необходимо задать во время собеседования, поэтому его необходимо освоить. Проанализируйте процесс распространения и связанные с ним знания всего сенсорного события. (Эта статья имеет много теоретических знаний, она скучная и требует большого терпения
Сенсорные методы, связанные с событиями
Сенсорные события обычно включают в себя следующие методы:
1、dispatchTouchEvent
Из комментариев в исходном коде видно, что этот метод в основном используется для распространения и доставки событий, когда он возвращает значение true, обрабатывает его от своего имени, передает событие себе, в противном случае передает его другим представлениям. Этот метод также является первым методом для выполнения события касания, от которого зависит, будут ли выполнены последующие.
2、onInterceptTouchEvent
Этот метод в основном уникален для viewGroup и используется для перехвата сенсорных событий, по умолчанию он возвращает false:
Вы можете видеть, что комментарии очень длинные и подробные. Я приведу некоторые важные замечания здесь:
- Он в основном используется для перехвата во время распределения событий, что эквивалентно перехватчику
- Если возвращается false или super, событие продолжает доставляться, и viewGroup каждого слоя, через который проходит событие, вызовет этот метод, чтобы спросить, следует ли перехватить
- Если он возвращает true, это означает, что он перехватывает событие, прекращает передачу его в дочернее представление и принимает собственное событие onTouchEvent.
- В отличие от onTouchEvent, перехват зависит от события down. Этот метод может перехватывать каждое событие.
- Как только событие перехватывается, последующие события перемещения и повышения доставляются непосредственно в onTouchEvent, и больше не будет запрашиваться перехват (то есть, onInterceptTouchEvent больше не вызывается)
- После того как событие будет перехвачено, дочернее представление получит событие отмены, чтобы восстановить предыдущее состояние и завершить текущий поток событий.
3、requestDisallowInterceptTouchEvent
Этот метод также используется для перехвата событий, который также является проприетарным методом viewGroup, но обычно он вызывается в дочерних представлениях. Согласно примечанию: Когда дочернее представление не хочет, чтобы его родительское представление перехватывало события через метод onInterceptTouchEvent, Вызов этого метода может привести к доставке и получению событий, и во всем потоке событий родительское представление и родительское представление, повышающееся, должны следовать этому правилу.
4、onTouch
Это также сенсорное событие, которое удобно для разработчиков. Согласно примечанию: этот метод вызывается, когда сенсорное событие отправляется в представление, которое вызывается перед передачей события в onTouchEvent.
5、onTouchEvent
Этот метод является последним методом, который действительно используется для обработки сенсорных событий, здесь вы можете написать свой собственный алгоритм сенсорных событий.
6、onClick
Это событие щелчка, с которым мы наиболее знакомы. Оно также относится к содержимому событий касания. Следует отметить, что оно выполняется в событии UP события onTouchEvent. Это последовательность выполнения onTouch, onClick и onTouchEvent, о которой мы поговорим ниже.
onTouch, onTouchEvent, последовательность выполнения onClick
Последовательность выполнения: onTouch—> onTouchEvent—> onClick. Примечание: onClick принимает событие напрямую и больше не отслеживает событие. Давайте проверим это на примере. Давайте установим событие прослушивания для представления:
И переопределить onTouchEvent:
Журнал печати выглядит следующим образом:
Подтвердите наш заказ, следующее вернет onTouch true:
Объясните, что onTouch сначала использует события. Если onTouchEvent возвращает true:
onClick не будет выполнен, указывая на то, что в событии UP onTouchEvent событие было использовано, поэтому последнее событие щелчка не выполняется, давайте посмотрим на исходный код:
Здесь очевидно, что onTouch имеет приоритет над выполнением onTouchEvent.
ExecuteClick — это событие onClick, которое выполняется. Вы можете видеть, что onClick выполняется в событии UP onTouchEvent, поэтому, если onTouchEvent возвращает true, событие используется, и этот код не будет выполнен, поэтому событие onClick Этого не произойдет, поэтому порядок отношений должен быть относительно ясным.
Сенсорная последовательность доставки событий
Давайте рассмотрим механизм потока всего сенсорного события, прежде всего:
Вы напуганы? Ха-ха, давайте проанализируем вышеизложенное через детальный анализ.
Изображение выше разделено на три слоя: Activity ——> ViewGroup ——> View, где ViewGroup имеет еще один метод onInterceptTouchEvent, чем два других. Стрелка указывает направление потока событий. Значение представляет собой возвращаемое значение метода, а зеленое поле потребления показывает, что событие было израсходовано, и в этот момент оно не будет передано или отслежено.
Присмотревшись к рисунку, мы можем суммировать следующие моменты:
1. Если событие не прерывается, весь поток событий представляет собой полную U-образную диаграмму
- События последовательно завершаются с помощью dispatchTouchEvent-> ViewGroup’s DispatchTouchEvent-> ViewGroup’sInInterceptTouchEvent-> View’s dispatchTouchEvent-> View’s onTouchEvent-> ViewGroup onTouchEvent-> Activity’s onTouchEvent.
2. Как только dispatchTouchEvent и onTouchEvent возвращают true, событие используется, событие исчезает, и оно не будет передано или отслежено.
3. Как только dispatchTouchEvent и onTouchEvent вернут false, событие будет отслеживаться до onTouchEvent родительского элемента управления, указывая, что они не обрабатывают
- dispatchTouchEvent возвращает false и true для Activity, поскольку он является получателем события верхнего уровня, в то время как ViewGroup и View возвращают super, передается вниз, return false — это событие обратного отслеживания onTouchEvent родительского элемента управления.
- onTouchEvent возвращает super для восходящего события отслеживания и возвращает false, чтобы указать, что он не обрабатывает его, поэтому это также восходящее событие отслеживания. Если в конце нет потребления, действие потребляет и событие исчезает.
4. Превосходством всех методов является возвращаемое значение по умолчанию, которое должно гарантировать, что весь поток событий завершен в соответствии с U-образной диаграммой.
5.onInterceptTouchEvent возвращает super по умолчанию. Мы знаем из исходного кода, что он возвращает false. По умолчанию не перехватывается событие. Это также соответствует здравому смыслу. Это может дать дочерним представлениям возможность перехватить событие. Возвращение true означает, что событие было перехвачено и получено Ваш собственный onTouchEvent для обработки, реализация по умолчанию для dispatchTouchEvent ViewGroup заключается в вызове собственного onInterceptTouchEvent, который может гарантировать, что события будут иметь возможность распространяться на ваш собственный onTouchEvent.
6.dispatchTouchEvent и onTouchEvent основаны на событии Down, чтобы определить, проходят ли последующие события сами по себе, то есть их собственное потребление. Если событие Down возвращает false или super, последующие события больше не проходят через себя, в том числе move, up, Если только после возврата true последующие события будут проходить через себя
Ниже мы используем демонстрацию, чтобы объяснить логику вышеприведенного рисунка. Сначала мы создаем новую ViewGroup, затем новый View и Activity. Перепишите их dispatchTouchEvent, onInterceptTouchEvent и onTouchEvent соответственно. Исходный код отображаться не будет. Это относительно просто. Следующим образом:
Сначала верните все в соответствии с супер по умолчанию, щелкните среднее представление, чтобы увидеть журнал (VG обозначает ViewGroup, V обозначает View):
Глядя на журналы, можно проанализировать, что U-образный маршрут согласуется с нашим.После того, как события передаются вниз и возвращаются назад, последнее событие используется Activity (последующее событие UP). Обратите внимание, что наше возвращаемое значение находится в последней строке метода, а не в событии DOWN, и журналы, созданные в этом событии, будут другими, что будет описано позже.
Ниже мы возвращаем true onView onTouchEvent:
Наш dispatchTouchEvent in View возвращает true:
Наше onTouchEvent в ViewGroup возвращает true:
Наш onInterceptTouchEvent в ViewGroup возвращает true, а onTouchEvent также возвращает true:
Можно заметить, что после перехвата все последующие события перемещения и вверх обрабатываются сами по себе, и onIntercepetTouchEvent больше не вызывается, а событие больше не передается дочернему представлению.
Теперь давайте вернем dispatchTouchEvent ViewGroup в true:
DispatchTouchEvent действия возвращает true или false:
Посредством вышеприведенного журнала, внимательно проанализируйте приведенную выше картинку еще раз, вы можете обнаружить, что процесс полностью согласован, и весь процесс легче запомнить в соответствии с чертежом.
Понимание о ACTION_DOWN
Выше было упомянуто, что, если событие используется dispatchTouchEvent и onTouchEvent, определяется в событии DOWN. Если DOWN не возвращает истину, последующие перемещения и вверх не будут возвращаться к двери снова. Давайте посмотрим на событие возврата до истины. :
Событие DOWN в onTouchEvent представления возвращает значение true:
Вы можете видеть, что последняя строка журналов — это больше, чем метод, который возвращает true в конце метода непосредственно выше. Остальные точно такие же. Это потому, что только down возвращает true, только последующие события проходят через себя, но события перемещения и вверх возвращают super, и Событие onTouchEvent в ViewGroup было пропущено, поэтому событие up возвращается к Activity. Возврат true в событиях перемещения и вверх не имеет эффекта возврата true в down. Давайте посмотрим на возвращаемое значение false:
Можно видеть, что последующие события перемещения и вверх не проходят сами по себе, поэтому событие down играет определенную роль в определении потока события.
Давайте посмотрим на ВНИЗ dispatchTouchEvent представления:
Можно видеть, что событие останавливается после того, как оно достигает dispatchTouchEvent для представления, поскольку оно возвращает здесь значение true, что означает, что событие здесь используется, и последующее событие UP также переходит к dispatchTouchEvent представления. Так как up возвращает super, оно отправляется После собственного onTouchEvent возвращаемое здесь супер тоже супер, поэтому прослеживает восходящее событие onTouchEvent.
Что если здесь возвращается false
Видно, что событие возвращается к onTouchEvent родительского элемента управления после dispatchTouchEvent представления, а затем продолжает трассировку, и последующие события UP не пройдут. Давайте посмотрим на DOWN onTouchEvent ViewGroup возвращает true:
Вы можете видеть, что событие завершилось в OnTouchEvent ViewGroup и не продолжило трассировку, и событие up также прошло само. Поскольку оно вернуло super, оно проследило до Activity.
OnInterceptTouchEvent помещается в следующем разделе, мы продолжаем возвращать DOWN dispatchTouchEvent ViewGroup в true:
Вы можете видеть, что событие используется в dispatchTouchEvent, оно не передается, а последующее повышение проходит через себя.
Таким образом, можно проанализировать, что после получения ACTION_DOWN вы будете получать последующие события, такие как ACTION_MOVE, ACTION_UP и т. Д. Необходимым условием является то, что событие должно быть использовано, то есть оно возвращает true. Если он возвращает значение true только в ACTION_DOWN, а другие события возвращают super, другие события не потребляются и будут продолжать прослеживаться вверх, но обязательно пройдут сам контроль потребления.
Понимание о onInterceptTouchEvent
Выше говорилось, что onInterceptTouchEvent не должен решать, потреблять ли в DOWN, как onTouchEvent. Он используется для перехвата, что эквивалентно переадресации, поэтому все события в нем могут быть перенаправлены, например, когда мы нажимаем список Одно из представлений, а затем и последующее скольжение, на этот раз все еще будет использовать метод onInterceptTouchEvent, но он будет перемещен (при условии, что вы не перехватили событие DOWN, то есть пропустили событие в дочернее представление), на этот раз Вы можете сделать перехват в событии перемещения, чтобы скользить по списку. Этот дизайн соответствует обычной логике. Давайте посмотрим на журнал (верните true в down):
Вы можете видеть, что он был остановлен напрямую и оставил свой собственный onTouchEvent. Так как супер был возвращен, событие прослеживается до Activity.
Посмотрите на возвращение true в движении (возвращение true в onTouchEvent, потому что событие DOWN представляет перехват, если оно не возвращает true, последующие перемещения не будут проходить через ViewGroup):
Вы можете видеть, что событие перемещения было успешно остановлено.
О появлении ACTION_CANCEL
В приведенной выше сцене onInterceptTouchEvent фактически есть еще один шаг, то есть onTouchEvent представления также должен возвращать true, что означает, что это щелчок в начале, затем пауза, скольжение пальца, и он становится слайдом, и перехватывается onInterceptTouchEvent. В это время Представление получит событие ACTION_CANCEL для восстановления его исходного нажатого состояния, посмотрите журнал:
Мы успешно смоделировали описанный выше сценарий. Событие передается в onTouchEvent представления. Когда система считает, что оно используется, палец скользит, а затем ViewGroup перехватывает слайд. В это время будет активирован дополнительный ACTION_CANCEL для передачи дочернему представлению и возобновления. Состояние детского взгляда, дизайн, можно сказать, очень умный, ха-ха
в конце концов
Ну, наконец-то закончил, я сказал так много, что не знаю, все ли это понимают, и есть детская обувь, которая не понимает, может оставить мне сообщение и, наконец, выпустить исходный код демо:
Источник