本文共 3811 字,大约阅读时间需要 12 分钟。
最近看到群里看到一个女生,讲述了她从开始选择Android,经过非常努力的学习和挣扎,然而最后面对当前的环境却不得不放弃。看完以后真的非常替她感觉惋惜,如果早几年入行可能结果会比现在好很多,但可惜,这就是现实。
这是一个做精品的时代了,不是当年出个产品就能拉投资骗点击的时代了。精品需要的是更专业的人才,也就是对APP开发人员的素质要求会更高,这个市场会回归一个正常的节奏,拿多少钱就是看能力,看产品。
android中事件分发机制是android中常见的问题,一般大家都知道view的分发事件是从view的Viewgroup(Parent)#dispatchTouchEvent
到Viewgroup(Parent)#onInterceptTouchEvent
再到View#dispatchTouchEvent
,然后到view的onTouchEvent
,最后又回到了Viewgroup(Parent)#onTouchEvent
。如果大家记不住方法名,可以直接说先是parent的分发到拦截再到view的分发,再到view的消费,最后到parent的消费
这样回答肯定是很浅显的,因为没有说出是否拦截、是否分发、是否消费的各种条件,没有涉及到各种action的分发情况,上面说的默认分发只是针对action_down的,因为view/viewgroup
各种super调用都是不进行分发、拦截、消费的,所以在没找到处理touch事件的view时候,是一直往上层view传递的,一直传到activity里面,下面我们再来整理一下:
如果viewgroup不进行分发,那么
action_down
、action_move
和action_up
只会执行到viewgroup的dispatchTouchEvent
,不分发的条件是dispatchTouchEvent
直接返回true或false,true和false的区别是true会执行action_down
、action_move
和action_up
,而如果直接返回false只会执行到action_down。并且后续的viewgroup的onInterceptTouchEvent
后续方法都不会被执行到。
关于为什么view/Viewgroup的dispatchTouchEvent
返回true的时候三个action都能执行到,而返回false的话,只能执行到action_down,这个需要到view/Viewgroup的父类中dispatchTouchEvent
找答案,该方法中会在action_down的时候调用dispatchTransformedTouchEvent
方法,而该方法是通过子view的dispatchTouchEvent方法的返回值来决定父类的dispatchTransformedTouchEvent
方法的返回值,而dispatchTransformedTouchEvent
的返回值会决定mFirstTouchTarget
是否为空,所以在action_down的过程中实际中通过子view的dispatchTouchEvent
方法返回值来确定mFirstTouchTarget
是否为空。这里贴出viewgroup中dispatchTransformedTouchEvent
方法的删减代码:
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel, View child, int desiredPointerIdBits) { ------------------ //省略了cancel部分的代码 ------------------------ //如果child为空,直接调用自己的dispatchTouchEvent方法,此时自己就相当于一个view,touch事件走自己的 if (child == null) { handled = super.dispatchTouchEvent(transformedEvent); } else { final float offsetX = mScrollX - child.mLeft; final float offsetY = mScrollY - child.mTop; transformedEvent.offsetLocation(offsetX, offsetY); if (! child.hasIdentityMatrix()) { transformedEvent.transform(child.getInverseMatrix()); } //返回值直接通过孩子来获取返回值 handled = child.dispatchTouchEvent(transformedEvent); } transformedEvent.recycle(); return handled;}
所以如果view/viewgroup的dispatchTouchEvent
方法返回false,表示在action_down的时候,父类的dispatchTransformedTouchEvent
方法返回false;如果返回true会调用addTouchTarget
方法,给mFirstTouchTarget
设置值:
private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) { final TouchTarget target = TouchTarget.obtain(child, pointerIdBits); target.next = mFirstTouchTarget; mFirstTouchTarget = target; return target;}
紧接着在在后面又会调用了:
这句只有在view/viewgroup的dispatchTouchEvent
返回false的时候,才会走这里,所以后面的action_move
和action_up
都会走这里,而此时传入的child=null,从上面代码可以看到,直接调用了父类的dispatchTouchEvent
方法。所以从这里不难看出在view/viewgroup的dispatchTouchEvent
返回false的时候直接调用了父类的dispatchTouchEvent
方法,因此只有action_down事件。
其实这道题考察大家对view的dispatchTouchEvent和view的onTouchEvent事件的处理流程,上面已经分析了想要view能执行到view的touch事件,那么必须要求view的dispatchTouchEvent
返回true,而dispatchTouchEvent
返回true要么是dispatchTouchEvent
直接返回true或者view的onTouchEvent
返回true。如果从效率上看,直接将dispatchTouchEvent
返回true就ok,而不需要再去关心onTouchEvent
方法。
关于拦截无非就是拦截或不拦截,而拦截的条件是返回true,不拦截是返回false或返回super.onInterceptTouchEvent,默认的super是返回false的,因此可以用super表示不拦截
viewgroup拦截实际是通过在dispatchTouchEvent
方法中,设置intercepted变量,如果在拦截方法里面返回true,那么intercepted为true,如果为true则在action_down的时候mFirstTouchTarget=null,那么此时是直接调用dispatchTransformedTouchEvent
传入的child=null,因此将事件交给了super.dispatchTouchEvent
,此时把它当成一个view来处理了。
我这里整理了一份完整的学习思维以及Android开发知识大全PDF,有需要的同学可以自行领取。
当然实践出真知,即使有了学习线路也要注重实践,学习过的内容只有结合实操才算是真正的掌握。
qq.com/doc/DSkNLaERkbnFoS0ZF)**
当然实践出真知,即使有了学习线路也要注重实践,学习过的内容只有结合实操才算是真正的掌握。
转载地址:http://esqlf.baihongyu.com/