【学习】Android中View的事件体系(上)——View的滑动和事件分发机制

三个维度,不太一样的View事件分发机制(滑动冲突) 个人博客原文链接,这里的排版阅读效果会更好哦~ 每一个Android开发者,都绕不开View的事件分发,理解好View的事件分发机制,有利于我们解决各种与设备触摸交互的问题,同时也利于我们实现更复杂、炫酷的自定义View效果。 关于Android View的事件分发机制,笔者打算分为三篇文章来描述,分别为: (1)Android View事件分发机制之概念理论篇 (2)Android View事件分发机制之源码解读篇 (3)Android View事件分发机制之滑动冲突实战解决篇 本文是第三篇:. 阅读详情

View的基础知识

什么是View

View是所有控件的基类,它是一种界面层控件的抽象,它代表了一个控件。除了View还有ViewGroup,它也继承了View,意味着View本身就可以是单个控件也可以是由多个控件组成的一组控件,通过这种关系形成了View树的结构。ViewGroup内部可以有子View,子View也可以是ViewGroup

View的位置参数

决定位置的四个属性
top(左上角横坐标)、 left(左上角纵坐标)、right(右下角横坐标)、bottom(右下角纵坐标),这些坐标都是相对于View的父容器来说的,因此它是一种相对坐标。在Android中,x轴和y轴分别向右和下。不仅Android,大部分显示系统都是按这个标准来定义坐标系。看下图
在这里插入图片描述

可得出宽高和坐标的关系
width=right-lfet
height=bottom-top

获得四个位置参数的方法

Left:getLeft(); 返回mLeft
Right:getRight(); 返回mRight
Top:getTop(); 返回mTop
Bottom:getBottom(); 返回mBottom

额外参数

从Android3.0开始,View增加了几个参数:x y,它们是View左上角的坐标,translationX和translationY,它们是View左上角相对于父容器的偏移量。这几个参数也是相对于父容器的坐标,并且translationX和translationY的默认值为0。View也为它们提供了get/set方法。
换算关系:x=left+translationX y=top+translationY。
需要注意:View在平移的过程中top和left表示的是原始左上角的位置信息,它们的值不会改变,此时发生改变的是x,y,translationX,translationY。

MotionEvent和TouchSlop

MotionEvent

手指接触屏幕后产生的一系列事件中,典型事件有3种
1.ACTION_DOWN–手指刚接触屏幕
2.ACTION_MOVE–手指在屏幕上移动
3.ACTION_UP–手机2从屏幕上松开的一瞬间

正常情况下,一次手指触摸屏幕的行为会触发一系列点击事件
1.点击屏幕后离开松开:DOWN->UP
2.点击屏幕滑动一会再松开,DOWN->MOVE->…MOVE->UP

通过MotionEvent对象我们可以得到点击事件发生的xy坐标。为此,系统提供了getX/getY(返回的是相对于当前View左上角的xy坐标)和getRawX/getRawY(返回的是相对于手机屏幕左上角的xy坐标)

TouchSlop

TouchSlop是系统所能识别出的被认为是滑动的最小距离,也就是说当两次滑动之间的距离小于这个常值,系统便不认为是在进行滑动操作,不同设备这个值可能是不同的。
获取该常量的方法:ViewConfiguration.get(getContext()).getScaledTouchSlop();
该常量的意义:当我们处理滑动时,可以利用这个常量来做一些过滤

VelocityTracker、GestureDetector、Scroller

1.VelocityTracker

速度追踪,用于追踪手指在滑动过程中的速度,包括水平和竖直方向的速度

使用方法

在View的onTouchEvent方法种追踪当前单击事件的速度
VelocityTracker v=VelocityTracker.obtain();
v.addMovement(event) //event是onTouchEvent方法的参数
接着,当我们先知道当前的滑动速度时,可采用如下方式获得当前的速度
v.computeCurrentVelocity(100);//调用get方法前必须先计算速度,即调用computeCurrentVelocity方法,这里的速度指一段时间内手指所滑过的像素数,参数为时间间隔(ms)
int x=(int)v.getXVelocity();
int y=(int)v.getYVelocity();
计算公式:速度=(终点位置-起点位置)/时间段
根据公式我们可以得出当手指逆着坐标系的正方向滑动时,所产生的速度就为负值。当不需要使用它时,调用clear和recycle方法来重置并回收内存

GestureDetector

手势检测,用于辅助检测用户的单击、滑动、长按、双击等行为。

使用方法

1.创建一个GestureDetector对象并实现OnGestureListener接口,根据需要还可以实现OnDoubleTapListener从而监听双击行为。(原书中的单参数的构造器已经被弃用) 看下图

在这里插入图片描述

可使用setIsLongpressEnabled(false)来解决长按屏幕后无法拖动的现象

2.接管目标View的onTouchEvent方法:在待监听View的onTouchEvent方法中
boolean consume=g.onTouchEvent(event);
return consume;
在这里插入图片描述

看上图注释可以看出g.onTouchEvent(event)如果消费/接管了当前事件会返回true

做完上面两步后,我们就可有选择地实现OnGestureListener和OnDoubleTapListener中的方法。 看下图
在这里插入图片描述

在这里插入图片描述

在开发中比较常用的有:onSingleTapUp(单击)、onFling(快速滑动)、onScroll(拖动)、onLongPress(长按)、onDoubleTap(双击)。在实际开发中可以GestureDetector,完全可以在View的onTouchEvent中实现所需的监听。如果只是监听滑动相关的,建议自己在onTouchEvent实现,如果要监听双击这些行为的话就使用GestureDetector。

Scroller

弹性滑动对象,用于实现View的弹性滑动。当我们使用View的scrollTo/scrollBy方法来进行滑动时,其过程是瞬间完成的,这个没有过渡效果的滑动用户体验不好。这个时候就可以使用Scroller来实现有过渡效果的滑动,其过程不是瞬间完成的,而是在一定的时间间隔内完成的。Scroller本身无法让View弹性滑动,它需要和View的computeScroll方法配合使用才能共同完成这个功能,它只是一个移动计算辅助类,用于跟踪控件滑动轨迹,最终还是通过View的scrollTo/By来完成。 看下图

在这里插入图片描述

在这里插入图片描述

基本使用流程

1.通过Seroller的startScroll开始一个滑动动画控制,里面进行一些轨迹参数的设置和计算
2.在调用startScroll后面调用invalidate()让视图重绘从而触发ViewGroup中的computeScroll被调用
3.在computeScroll中,首先调用Scroller中的computeScrollOffest方法,里面根据当前消耗时间进行轨迹坐标的计算,然后取得计算当前滑动的偏移坐标,调用View的serollTo进行滑动控制

View的滑动

滑动几乎是应用的标配,掌握滑动的方法是实现绚丽的自定义控件的基础。

三种方式可以实现View的滑动

1.通过View本身的scrollTo/By

在这里插入图片描述

看上图,我们可以看到scroolBy实际上也是调用了scrollTo。
在这里插入图片描述

看上图scrollBy实现了基于当前位置的相对滑动,而scrollTo实现了基于所传递参数的绝对滑动。

理解滑动过程中View内部的mScrollX和mScrollY的改变规则

这两个属性可以通过getScrollX/Y得到。在滑动过程中,mScrollX的值总是等于View左边缘和View内容左边缘在水平方向的距离,而mScrollY的值总是等于View上边缘和View内容上边缘在竖直方向的距离。View边缘是指View中的内容的边缘,scrollTo和scrollBy只能改变View内容的位置而不能改变View在布局中的位置。两个属性的单位都是像素,并且当View左边缘在View内容左边缘的右边时,mScrollX为正值,当View上边缘在View内容上边缘的下边时,mScrollY为正值,反之为负值。也就是如果从左向右滑动,那么mScrollX为负值,反之为正值,如果从上往下滑动,mScrollY为负值,反之为正值。 看下图

在这里插入图片描述

2.使用动画

通过动画我们能够让一个View进行平移,而平移就是一种滑动,使用动画来移动View,主要是操作View的translationX和translationY属性,既可以采用传统的View动画,也可以采用属性动画。
在这里插入图片描述

View动画是对View的影像做操作,并不能真正改变View的位置参数,包括宽/高,,如果希望动画后的状态得以保留还必须将fillAfter属性设置为true,否则动画完成后其动画效果会消失。使用属性动画不会有这个问题。

3.改变布局参数

改变布局参数即是改变LayoutParams。比如我们想把一个view向右平移100px,我们只需要将这个View的LayoutParams里的marginLeft参数的值增加100px即可

各种滑动方式的对比

scrollTo/By是View提供的原生方法,其作用是专门用于View的滑动,它可以比较方便地实现滑动效果并且不影响内部元素的单击事件,但不能滑动View本身。使用属性动画没有明显缺点,View动画不能改变自身属性。改变布局没有明显缺点,它的主要适用对象是一些具有交互性的View。看下图

在这里插入图片描述

弹性滑动

思想

将一次大的滑动分成若干次小的滑动并在一个时间段内完成

Scroller

前面已经介绍过它的使用方法,接下来分析源码 看下图
在这里插入图片描述

之前将Scroller的时候我们构造一个Scroller对象并调用它的startScroll方法时,Scroller其实什么也没做,它只保存了我们传递的参数。startX和stratY表示滑动的起点,dx,dy表示滑动的距离,duration表示滑动时间,,这里的滑动指的是View内容滑动而非View本身位置的改变。 可以看到仅仅调用startScroll是无法让View滑动的,让View弹性滑动的是startScroll方法下面的invalidate方法,它会导致视图重绘,在View的draw方法中又会去调用computeScroll方法,它在View中是一个空实现,因此需要我们自己去实现,上面的代码已经实现了computeScroll方法,正是因为它才能实现弹性滑动。当View重绘后会在draw方法中调用computeScroll,而computeScroll又会去向Scroller获取当前的scrollX和scrollY,然后通过scrollTo方法实现滑动,接着又调用postInvalidate方法进行第二次重绘,这一次重绘过程和第一次一样,然后继续向Scroller获取当前的ScrollX和ScrollY,并通过scrollTo方法滑动到新的位置,如此反复知道整个滑动过程结束。

computeScrollOffest的实现

在这里插入图片描述

看上图,留意timePassed和mDuration,这个方法会根据时间的流逝的百分比计算出scrollX和scrollY改变的百分比并算出当前的值,它返回true时表示滑动还未结束,false时表示滑动结束。

总结

Scroller本身不能实现View的滑动,需要配合View的computeScroll方法才能完成弹性滑动的效果,他不断地让View重绘,而每一次重绘距滑动起始时间会有一个时间间隔,通过这个间隔Scroller就可以得出View当前的滑动位置,知道了滑动位置就可以通过scrollTo方法完成View的滑动。就这样,View的每一次重绘都会导致View进行小幅度的滑动,而多次小幅度的滑动就组成了弹性滑动。

动画

我们可以利用动画的特性去完成动画本身完成不了的东西。
在这里插入图片描述

看上图,这个动画本质上没有作用于任何View,而是View利用动画的完成比例来计算出View要滑动的距离。

使用延时策略

核心思想

通过发送一系列延时信息从而达到一种渐进式的效果,具体来说可以使用Handler或View的postDelayed方法,也可以使用现成的sleep方法。对于postDelayed来说,我们可以通过它延时发送消息然后再消息中来进行View的滑动,如果接连不断发送这种延时信息就可以实现弹性滑动的效果。对于sleep方法来收,通过在while循环中不断地滑动View和sleep就可以实现弹性滑动。

View的事件分发机制

点击事件的传递规则

所谓点击事件的分发,其实就是对MotionEvent事件的分发过程,即当一个MotionEvent产生了以后,系统需要把这个事件传递给一个具体的View,而这个传递的过程就是分发过程。点击事件的分发过程由三个方法来共同完成

1.public boolean dispatchTouchEvent(MotionEvent ev)

用来进行事件的分发。如果事件能够传递给当前的View,那么此方法一定会被调用,返回结果受当前View的onTouchEvent和下级View的dsipatchTouchEvent影响,表示是否消耗当前事件

2.public boolean onInterceptTouchEvent(MotionEvent event)

在上述方法的内部调用,用来判断是否拦截某个事件,如果当前View拦截了某个事件,那么在同一个时间序列中,此方法不会被再次调用,返回结果表示是否拦截当前事件

3.public boolaean onTouchEvent(MotionEvent event)

在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一个时间序列中,当前View无法再次接收到事件。

它们的关系

可以用以下伪代码来表示

	boolean consume=false;
	if(onInterceptTouchEvent(ev)){
	consume=onTouchEvent(ev)
}else{
	consume=child.dispatchTouchEvent(ev)
}
	return consume;
}

对于一个根ViewGroup来说,点击事件产生后,首先会传递给它,此时它的的dispatchTouchEvent就会被调用,如果这个ViewGroup的onInterceptTouchEvent方法返回true就表示它要拦截当前事件,接着时间就会交给这个ViewGroup处理,即它的onTouchEvent会被调用,如果ViewGroup的onInterceptTouchEvent方法返回flase表示它不拦截当前事件,此时当前时间就会继续传递给它的子元素,接着子元素的dispatchEvent方法就会被调用,如此反复直到事件被处理。

当一个View需要处理事件时,如果它设置了OnTouchListener,那么OnTouchListener中的onTouch方法会被回调。这时时间如何处理还要看onTouch的返回值,如果返回false,则当前View的onTouchEvent方法会被调用,如果返回true,那么onTouchEvent方法不会被调用。由此可见,给View设置的OnTouchListener,其优先级比onTouchEvent方法高。在onTouchEvent方法中,如果当前设置的有OnClickListener,那么它的onClick方法会被调用。可以看出,平时我们常用的OnClickListener优先级最低,处于事件传递的尾端。

当一个点击事件产生后,它的传递过程遵循如下顺序:Activity->Window->View,即事件总是先传递给Activity,Activity再传递给Window,最后Window再传递给顶级View,顶级View接收到事件后,就会按照事件分发机制去分发事件。考虑一种情况,如果一个View的onTouchEvent返回false,那么它的父容器的onTouchEvent将会被调用,以此类推,如果所有的元素都不处理这个事件,那么这个事件最终会传递给Activity处理,即Activity的onTouchEvent方法会被调用。约等于上级抛任务给下级,下级搞不定,只能交给水平更高的上级,再不行就交给上级的上级去解决。

事件传递机制的结论

1.同一时间序列是指从手指接触屏幕的那一刻起,到手指离开屏幕的那一刻结束,在这个过程中所产生的一系列事件,这个事件序列以down事件开始,中间含有数量不定的move事件,最终以up事件结束。

2.正常情况下,一个时间序列只能被一个View拦截且消耗,这一条的原因可以参考第三点,因为一旦一个元素拦截了此事件,那么同一个事件序列内的所有事件都会直接交给它处理,因此同一个事件序列中的事件不能分别由两个View同时处理,但是通过特殊手段可以做到,比如一个View将本该自己处理的事件通过onTouchEvent强行传递给其他View处理。

3.某个View一旦决定拦截,那么这一个事件序列都只能由它来处理,并且它的onInterceptTouchEvent不会再被调用。也就是说当一个View决定拦截一个事件后,系统会把同一个事件序列内的其他方法都直接交给它来处理,因此就不用再调用onInterceptTouchEvent去询问它是否要拦截了。

4.某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件(onTouchEvent返回false),那么同一事件序列的其他事件都不会交给它来处理,并且事件将重新交由它的父元素去处理,即父元素的onTouchEvent会被调用,意思是事件一旦交给一个View处理,那么它就必须消耗掉,否则同一事件序列中剩下的事件就不再交给它来处理了。

5.如果View不消除ACTION_DOWN以外的其他事件,那么这个点击事件会消失,此时父元素的onTouchEvent并不会被调用,并且当前View可以持续收到后续的事件,最终这些消失的点击事件会传递给Activity处理。

6.ViewGroup默认不拦截任何事件,其源码中的onInterceptTouchEvent方法默认返回false。

7.View没有onInterceptTouchEvent方法,一旦由点击事件传递给它,它的onTouchEvent就会被调用。

8.View的onTouchEvent默认都会消耗事件(返回true),除非它是不可点击的(clickable和longClickable同时为false)。View的longClickable属性默认为false,clickable属性要分情况,比如Button的clickable属性默认为true,而Textview默认为false。

9.View的enable属性不影响onTouchEvent的默认返回值。哪怕一个View是disable状态,只要它的clickable或者longClickable有一个为true,它的onTouchEvent就返回true。

10.onClick会发生的前提是当前View是可点击的,并且它收到了down和up事件。

11.事件传递过程是由外向内的,事件总是先传递给父元素,然后再由父元素分发给子View,通过requestDisallowInterceptTouchEvent方法可以在子元素干预父元素的事件分发过程,但是ACTION_DOWN除外。

事件分发的源码分析

1.Activity对点击事件的分发过程

点击事件用MotionEvent来表示,当一个点击操作发生时,事件最先传递给当前Activity,由Activity的dispatchTouchEvent来进行事件分发,具体工作由Activity内部的Window完成。Window会将事件传递给decorview,decorview一般是当前界面的底层容器(即setContentView所设置的View的父容器),通过Activity.getWindow.getDecorView()可以获得。
在这里插入图片描述

首先事件开始交给Activity所附属的Window进行分发,如果返回true,整个事件循环就结束了,返回false意味着事件没人处理,所有View的onTouchEvent都返回了false,,那么Activity的onTouchEvent就会被调用。

接下来看Window是如何将事件传递给ViewGroup的,通过源码可得出Window是个抽象类,而Window的superDispatchTouchEvent方法也是个抽象方法。而Window的实现类其实是PhoneWindow。Window类可以控制顶级View的外观和行为策略,它的唯一实现位于android.policy.PhoneWindow中,当你要实例化这个Window类的时候,你并不知道它的细节,因为这个类会被重构,只有一个工厂方法可以使用。
在这里插入图片描述
)
从上图可以看到PhoneWindow将事件直接传递给了DecorView
在这里插入图片描述

通过((ViewGroup)getWindow().getDecorView().findViewById(android.R.id.content)).getChildAt(0)这种方式可以获取Activity所设置的View,这个mDecor显然就是getWindow().getDecorView()返回的View,而我们通过setContentView设置的View是它的一个子View。目前事件传递到了DecorView这里,由于DecorView继承自FrameLayout且是父View,所以最终时间会传递给View。换句话说,时间肯定会传递到View,不然应用如何相应点击事件呢?重点是事件到了View之后应该如何传递。从这里开始事件已经传递到顶级View了,即在Activity中通过setContentView所设置的View,顶级View也叫根View,一般来说都是ViewGroup。

顶级View对点击事件的分发过程

概述:点击事件到达顶级View,会调用ViewGroup的dispatchTouchEvent方法,ruoguodingjiViewGroup拦截事件即onInterceptTouchEvent返回true,则事件由ViewGroup处理,如果此时ViewGroup的mOnTouchListener被设置,则onTouch会调用,否则onTouchEvent被调用。也就是说都提供的话onTouch会屏蔽onTouchEvent。在onTouchEvent中,如果设置了mOnClickListener,则onClick会被调用。如果顶级ViewGroup不拦截事件,事件会传递到它所在的点击事件链上的子View,此时子View的dispatchTouchEvent会被调用。到此位置,事件已经从顶级View传递给了下一层View,如此循环,完成整个事件的分发。
ViewGroup对点击事件的分发过程主要实现在ViewGroup的dispatchTouchEvent方法中。方法较长,截取部分分析 见下图
在这里插入图片描述

当事件类型为ACTION_DOWN或mFirstTouchTarget!=null时ViewGroup会判断是否要拦截当前事件。当ViewGroup的子元素成功处理时,mFirstTouchTarget会被赋值并指向子元素。换种方式说,当ViewGroup不拦截事件并将事件交由子元素处理时mFirstTouchTarget!=null。反过来,一旦事件由当前ViewGroup拦截时,mFirstTouchTarget!=null不成立,那么当DOWN事件到来时ViewGroup不会再被调用,并且同一序列的其他事件默认交由它处理。

特殊情况

FLAG_DISALLOW_INTERCEPT标记位,通过requestDisallowInterceptTouchEvent方法来设置,一般用于子View中。一旦设置后,ViewGroup将无法拦截除了DOWN以外的事件。(因为DOWN会重置该标记位,导致View中设置的这个标记位无效)所以当面对ACTION_DOWN事件时,ViewGroup总是会调用自己的onInterceptTouchEvent方法来询问自己是否要拦截事件。
在这里插入图片描述

上图遇到DOWN事件时进行了重置。

结论

当ViewGroup决定拦截事件后,那么后续的点击事件将会默认交给它处理并且不再调用它的onInterceptTouchEvent方法,这证实了FLAG_DISALLOW_INTERCEPT的作用是让ViewGroup不再拦截事件,前提是ViewGroup不拦截DOWN事件。onInterceptTouchEvent不是每次时间都会被调用的,如果我们想提前处理所有的点击事件,要选择dispatchTouchEvent方法,只有这个方法能确保每次都会被调用。前提是事件能够传递到当前的ViewGroup。
在这里插入图片描述

上图中当ViewGroup不拦截事件时,首先遍历ViewGroup的所有子元素,然后判断子元素是否能够接收到点击事件。判断是否能接受点击事件主要有两点来衡量1.子元素是否在播放动画和点击事件的左边是否落在子元素的区域内。如果某个子元素满足这两个条件,事件就会传递给它来处理。dispatchTransformedTouchEvent实际上调用的就是子元素的dispatchTouchEvent方法。其参数的child在不是null的情况下会调用child.dispatchTouchEvent方法,这样事件就交由子元素处理了,从而完成了一轮事件分发。

在这里插入图片描述

当子元素的dispatchTouchEvent返回true,mFirstTarget就会被赋值然后跳出循环

在这里插入图片描述

这几行代码完成了mFirstTouchTarget的赋值并终止对子元素的遍历。如果子元素的dispatchTouchEvent返回false,ViewGroup就会把事件分发给下一个子元素(如果有下一个子元素)
其实mFirstTarget真正的复制过程是在addTouchTarget内部完成,从它的内部结构可以看出,它是一种单链表结构。mFirstTarget是否被赋值直接影响到ViewGroup的拦截策略,如果它为null,那么ViewGroup就默认拦截接下来同一序列的所有点击事件
在这里插入图片描述

如果遍历所有子元素后事件都没有被合适地处理原因
1.ViewGroup没有子元素
2.子元素处理了点击事件,但是在dispatchTouchEvent中返回了false,这一般是因为子元素在onTouchEvent中返回了false。
在这两种情况下ViewGroup会自己处理点击事件。

在这里插入图片描述

上图child为null之后,会转到View的dispatchTouchEvent方法,即点击事件交由View来处理

View对点击事件的处理过程(这里的View不包含ViewGroup)

这里的View是一个单独的元素,没有子元素,因此无法向下传递事件,只能自己处理事件。

在这里插入图片描述

上图,首先它会判断有没有设置OnTouchListener,如果onTouchListener中的onTouch方法返回true,那么onTouchEvent就不会被调用,可见onTouchListener的优先级高于onTouchEvent,这样做的好处是方便在外界处理点击事件。
接着分析onTouchEvent的实现

在这里插入图片描述

上图当View处于不可用状态下时View照样会消耗点击事件,尽管它看起来不可用。

在这里插入图片描述

下图,接着如果View设置有代理,那么还会执行TouchDelegate的onTouchEvent方法,其工作机制与OnTouchListener类似。

在这里插入图片描述

在这里插入图片描述

上图当View的CLICKABLE和LONG_CLICKABLE有一个为true时,那么它就会消耗这个事件,返回true,不管它是不是DISABLE状态。当UP事件发生时,会触发performClick方法,如果View设置了OnClickListener,那么performClick方法内部会调用它的onClick方法。看下图

在这里插入图片描述

View的LONG_CLICKABLE属性默认为false,而CLICKABLE属性是否为false和具体View有关,通过setClickable和setLongClickable可以改变它们的属性。setOnClickListener会自动将View的CLICKABLE设为true,setOnLongClickListener会自动将View的LONG_CLICKABLE设为true。看下图
在这里插入图片描述

Android View体系(五)从源码解析View的事件分发机制 三年前写过事件分发机制的文章但是写的不是很好,所以重新再写一篇,关于事件分发机制的文章已经有很多,但是希望我这篇是最简洁、最易懂的一篇。 阅读详情

相关推荐

【Android】View的事件分发机制

`dispatchTouchEvent(MotionEvent event)` 方法是事件分发的入口。 - 每当事件产生时(如点击、滑动),系统会将该事件封装成一个 `MotionEvent` 对象,并通过 `dispatchTouchEvent` 方法传递给根视图(通常是 `Activity` 中的 `DecorView`)。 - 在 `dispatchTouchEvent` 中,事件会根据层级逐层传递给子视图,直到找到可以处理事件的视图为止。 - 若 `dispatchTouchEv

Patrick_yuxuan的博客 1633

Android中的View的事件传递机制

Android中的View的事件传递机制

QYgujingjing的专栏 1004

Android——View的事件体系(一)View的滑动

主要介绍内容: View的基础知识 View的位置参数 MotionEvent 和 TouchSlope VelocityTracker、GestureDetector 和 Scroller View的滑动 使用scrollTo/scrollBy 使用动画 改变布局参数 各种滑动方式的对比 弹性滑动 使用Scroller 通过动画 使用延时策略 View的事件分发机制 点击事件的传递规则 事

AkaiC的博客 3026

View基础知识总结

目录 一、自定义View分类 二、View的绘制流程 三、onMeasure (1)onMeasure方法简介 (2)MeasureSpec简介 (3)getMeasuredWidth()与getWidth()区别 (4)获取子控件margin方法 三、onLayout 四、View的位置参数 ​ 五、View的滑动 六、自定义view滑动冲突 1.外部拦截法 七、Paint常用方法 八、Canvas 1、常用的基本方法 2、 drawPath绘制路径 (1)直线路径 .

MR_LABO的博客 4723

Android——View的事件体系(二)View的事件分发机制

主要介绍内容: View的事件分发机制 点击事件的传递规则 事件分发的源码解析 View的滑动冲突 常见的滑动冲突场景 滑动冲突的处理规则 滑动冲突的解决方式 在上一章中我们已经介绍了 View 的基础知识以及 View 的滑动,想了解的请戳 Android——View的事件体系(一)View的滑动 这里本节将介绍 View 的一个核心知识点:事件分发机制。在真正进入详细探讨之前,大家

AkaiC的博客 1305

View的事件体系——View的事件分发机制

View的事件分发机制 事件分发机制是View事件体系中的核心知识点,View的滑动冲突问题的解决方法就是基于View的分发机制,因此理解掌握View的分发机制是十分重要的。 1.点击事件的传递规则 《View的事件体系——View的基础知识》一文中我们已经介绍了MotionEvent,即手指触碰屏幕后所产生的一系列事件。 所谓的事件分发机制实质就是对MotionEvent事件的分发过程,也就是说当一个MotionEvent产生后,系统需要把这个事件传递到一个具体的View处理,而这个过程就称为分发过程。

AthonyDavis的博客 435

父布局与子布局控件的实现响应点击事件冲突问题。

布局类: 一:以RelativeLayout为例 1,在代码中加入如下红色代码,不然会被包含在其中的控件把焦点抢占,此时子控件无需设置clickable和focuseable             android:id="@+id/relativeLayout"             android:layout_height="wrap_content

麻仓叶会打码 6969

ROS机器人全覆盖路径规划实战:6种ipa算法对比与选型指南(附避坑经验)

本文深入对比了ROS中ipa_coverage_planning功能包集成的6种全覆盖路径规划算法,包括牛耕分解、栅格旅行商、神经网络、局部能量最小、轮廓线和凸感知放置。文章从覆盖率、重复率、计算效率、动态避障等核心工程指标出发,提供了基于不同场景(如静态/动态环境、规则/复杂布局)的实战选型指南,并分享了神经网络和局部能量最小等关键算法的参数调优与避坑经验,旨在帮助开发者根据实际需求选择并优化最合适的ipa覆盖算法。

perl8的博客 363

Android中的View的事件分发机制

View的事件分发机制

xiaokang666的博客 2347

01 ArcGIS空间分析--水文分析--利用水文分析方法提取山谷山脊线

ArcGIS空间分析的一个特别好的分析教程是汤国安老师的空间分析的内容。 实例与练习 练习1. 利用水文分析方法提取山脊、山谷线 1. 背景:山脊线、山谷线是地形特征线,它们对地形、地貌具有一定的控制作用。它们与山顶点、谷底点以及鞍部点等一起构成了地形及其起伏变化的骨架结构。因此在数字地形分析中,山脊线和山谷线以及

Meditation 1万+

webpack性能优化-optimization.splitChunks.chunks中的“all“、“async“和“initial“

最初,chunks(以及内部导入的模块)是通过内部 webpack 图谱中的父子关系关联的。CommonsChunkPlugin 曾被用来避免他们之间的重复依赖,但是不可能再做进一步的优化。 ——摘自 webpack 从 webpack v4 开始,移除了 CommonsChunkPlugin,取而代之的是 optimization.splitChunks。 而关于 optimization.splitChunks 中的chunks,webpack 官方文档却没有很好的进行举例解释,只说明了 async.

程序员秋风的博客 3137

解锁Android View事件分发机制:从原理到实战

在 Android 中,用户与界面的交互操作,如点击、滑动、长按等,都会产生触摸事件,这些事件被封装成MotionEvent对象。MotionEvent包含了丰富的信息,如触摸的坐标、触摸的类型、触摸的时间等,开发者可以通过这些信息来处理用户的操作。:手指刚接触屏幕时触发,这是一个事件序列的开始。在点击操作中,当手指按下屏幕的瞬间,就会产生ACTION_DOWN事件。它是事件处理的起点,后续的其他事件往往基于此展开。

顾林海 4551

从零搭建 AI 运维 Agent:告警自动诊断 + 修复的完整技术方案

适合读者:管理 5-50 台服务器的运维/SRE 工程师、技术负责人 技术栈:FastAPI + React + PostgreSQL + Redis + DeepSeek 关键词:AI运维、AIOps、自动化运维、智能告警、告警修复、Runbook自动化、DevOps、SRE、DeepSeek运维

weixin_38359457的博客 1640

Android View事件分发

什么是View事件分发?将点击事件(MotionEvent)传递到某个具体的View或者ViewGroup处理的过程。事件分发是向下传递的,也就是父到子的顺序,当用户触摸屏幕时(View或ViewGroup派生的控件),将产生点击事件(Touch事件)。Touch事件相关细节(发生触摸的位置、时间、历史记录、手势动作等)被封装成MotionEvent对象。

Android 领域开发程序员,希望通过写博客的方式不断的总结提升自己,大家共同进步哦! 1726

SAP 经营范围(Operating Concern) 和业务范围 (Business Area) 在核算架构或是管理架构中的区别和联系分别是什么 请给具体的示例

摘要:SAP系统中,业务范围(Business Area)和经营范围(Operating Concern)在核算架构中具有不同功能。业务范围是FI/CO共用维度,用于跨公司码的业务线核算(如电子产品、机械设备),支持内部管理和简单对外报表。经营范围则是CO-PA专属维度,聚焦获利能力分析,可细化到产品+客户+区域组合(如分析手机在华东区域的获利情况)。两者存在层级关联:经营范围包含业务范围作为基础维度,业务范围数据会传递至经营范围进行深度分析。实际应用中需先配置业务范围,再设置经营范围并关联相关维度,共同支

金牌架构师 96

小程序数据采集(3):PC端微信小程序降维调试与流量数据获取详解

本文提出了一种针对PC端微信小程序的逆向分析方法,通过利用PC端基于Chromium架构的天然优势,实现无需Root的降维打击。文章详细介绍了如何开启CEF远程调试协议、基于DevTools Protocol实现流量劫持、对抗PC端安全防线以及获取小程序本地存储数据的技术方案。相比移动端严苛的环境,PC端小程序在调试接口、网络拦截和数据存储等方面存在显著漏洞,为爬虫开发提供了更便捷的突破口。

数据知道的博客 827

Android View的事件分发机制

Android View的事件分发机制

m0_74448051的博客 1153

基于YOLOv10深度学习的花生种子霉变检测系统

YOLO(You Only Look Once)是当前最先进的目标检测算法之一,具有快速、精准的特性。YOLOv10是YOLO系列的最新版本,相较于之前的版本,YOLOv10在特征提取、模型精度和速度上都有了显著的提升。YOLOv10采用了更深的卷积神经网络、更多的跨层特征融合方法,使得其在不同尺寸物体的检测和复杂场景的处理上都表现出了优异的性能。YOLOv10特别适合应用在需要快速处理并检测大量图像的任务中,如花生种子霉变检测等,能够实现精准、高效的检测。

2201_76125393的博客 648

《Android View 的事件分发机制解析》

前言: 用户按下触摸屏幕的事件。ACTION_UP: 用户抬起手指的事件。: 用户在屏幕上移动手指的事件。: 事件被取消,例如由于系统的其他操作。: 当已经有一个手指按下的情况下,另一个手指按下会产生该事件;: 多个手指同时按下的情况下,抬起其中一个手指会产生该事件;

weijiangbc0的博客 1456

上午题目复习ing

无线局域网,11b是常用的,2.4ghz,后来改进5ghz,有些字段可以工作在5g的字段802.11/11a/1h/11n,,,,,11b和11g还在2.4ghz工作。数据链路层 传输服务,数据链路维护,差错控制,arp ip到mac,rarp反过来,token ring,x.25,atm,ethernet,蓝牙10m,简化因特网,分散式网,快调频,短包,点对点,点多多点,2.4ghz,最高速率1mb/s。gsm:是时分多址,900m-1800m,微蜂窝是市区,微微风是室内,伞是盲点,

weixin_47120900的博客 894

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Android View事件分发机制详解

事件分发遵循一个自顶向下传递,再自底向上回溯的过程,就像一个包裹从公司前台(顶层 View)开始,一层层向下传递到可能签收的部门(具体 View),如果没人签收就一层层退回来。)事件的核心流程,它决定了触摸事件如何从系统传递到具体的 View 并被消费。掌握 Android View 事件分发机制是成为熟练 Android 开发者的重要一步,尤其是在处理复杂 UI 交互时。Android 的 View 事件分发机制是处理用户触摸(既是容器也是 View,具有拦截事件的能力。),每层是一个部门 (

JMY_2016的博客 1332

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Android View事件分发机制 onTouch和onTouchEvent区别 以及解决滑动冲突的思路

参考: https://www.jianshu.com/p/7d50a6b0b6af 总结一下: 子View中的监听事件优先级: OnTouchListener---->OnTouchEvent---->OnCLickListener 如果优先级高的拦下事件,就不会再传递给后面的监听事件 1.Touch事件分发中只有两个主角:ViewGroup和View。View...

emmmsuperdan的博客 4246

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Android View的事件分发机制简单理解

前言 在开发过程中遇到的滑动冲突,例如ViewPager和横向RecyclerView,滑动ViewPager发现RecyclerView滑动不了,或者ViewPager和ListView,能滑动ListView确发现水平方向的滑动失效。滑动冲突的解决方法都是基于事件分发机制,本文我将对近期学到的事件分发机制内容进行理解和总结。 1.MotionEvent 要理解View的事件分发机制,就需要先了...

Yuki-r的博客 943

【Android】结合View的事件分发机制解决滑动冲突

由此我们可以总结出事件分发机制的过程:对于一个ViewGroup来说,点击事件产生后,首先传给它,调用它的dispatchTouchEvent,如果onInterceptTouchEvent返回true,表示拦截该事件,即调用onTouchEvent;如果onInterceptTouchEvent返回false,表示不拦截该事件,事件继续向下传递,调用子元素的dispatchTouchEvent,直到事件被处理。父容器不拦截任何事件,所有事件都传递给子元素,如果子元素需要就消耗掉,否则交给父容器处理。

2401_87463988的博客 916
上一篇: 【学习总结】Android的IPC机制(下)——Android的IPC方式
下一篇: 【学习】Android中View的事件体系(下)——滑动冲突
Panic  Lin
博客等级 码龄6年 81粉丝 64原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值