跟touch事件相关的3个方法:
public boolean dispatchTouchEvent(MotionEvent ev); //用来分派event
public boolean onInterceptTouchEvent(MotionEvent ev); //用来拦截event
public boolean onTouchEvent(MotionEvent ev); //用来处理event
拥有这三个方法的类:
Activity类: |
Activity |
dispatchTouchEvent(); onTouchEvent(); |
View容器(ViewGroup的子类): |
FrameLayout、LinearLayout…… ListView、ScrollVIew…… |
dispatchTouchEvent(); onInterceptTouchEvent(); onTouchEvent(); |
View控件(非ViewGroup子类): |
Button、TextView、EditText…… |
dispatchTouchEvent(); onTouchEvent(); |
三
个方
法的用法:
dispatchTouchEvent() |
用来分派事件。 其中调用了onInterceptTouchEvent()和onTouchEvent(),通常不重写该方法 |
onInterceptTouchEvent() |
用来拦截事件。 ViewGroup类中的源码实现就是{return false;}表示不拦截该事件, 事件将向下传递(传递给其子View); 若手动重写该方法,使其返回true则表示拦截,事件将终止向下传递, 事件由当前ViewGroup类来处理,就是调用该类的onTouchEvent()方法 |
onTouchEvent() |
用来处理事件。 返回true则表示该View能处理该事件,事件将终止向上传递(传递给其父View); 返回false表示不能处理,则把事件传递给其父View的onTouchEvent()方法来处理 |
【注】:ViewGroup的某些子类(GridView、ScrollView...)重写了onInterceptTouchEvent()方法,当发生ACTION_MOVE事件时,返回true进行拦截。
为了演示,重写了4个类:
总统 --> MyActivity
省长 --> MyFrameLayout
市长 --> MyLinearLayout
农民 --> MyTextView
【举个通俗易懂的例子】:
总统对省长说:我要吃红烧鱼
省长对市长说:你作个红烧鱼
市长对县长说:你作个红烧鱼
县长对农民说:你作个红烧鱼
……(农民作呀作,没作出来)
农民说:我尽力了,但真心不会作呀,饶了我吧
县长说:你个笨蛋,下次不找你了,看我来作
……(县长作呀作,没作出来)
县长对市长说:我尽力了,很是抱歉,我不会作
市长说:你个废物,要你何用,只能我本身来作了
……(市长作呀作,作成功了)
市长对省长说:红烧鱼作好了
省长说:不错,下次有事还找你
省长对总统说:红烧鱼作好了
总统说:不错,下次有事还找你
---------------------------
总统对省长说:我要吃水煮鱼
省长对市长说:你作个水煮鱼
市长说:县长连红烧鱼都搞不定,此次就不找他了,我本身亲自来作
……(市长作呀作,又成功了)
市长对省长说:水煮鱼作好了
省长说:不错,下次有事还找你
省长对总统说:水煮鱼作好了
总统说:不错,下次有事还找你
---------------------------
- 按常理,领导都会把任务向下分派,一旦下面的人把事情作很差,就不会再把后续的任务交给下面的人来作了,只能本身亲自作,若是本身也作不了,就只能告诉上级不能完成任务,上级又会重复他的过程。
- 另外,领导都有权利拦截任务,对下级隐瞒该任务,而直接本身去作,若是作不成,也只能向上级报告不能完成任务。
【1】TextView的clickable属性默认是false,因此TextView的onTouchEvent()方法默认返回false,程序输出以下:

事件传递示意图:
【2】把TextView的clickable属性手动改为true,或者直接重写onTouchEvent()方法,使其返回true,程序输出以下:
事件传递示意图:
【3】手动重写LinearLayout的onInterceptTouchEvent()方法,使其返回true,拦截事件,再重写onTouchEvent()方法,返回true,程序输出:
事件传递示意图:
(1)这一系列的传递流程都是dispatchTouchEvent()方法来控制的,若是不人为地干预,事件将由上自下依次传递(由于默认是返回false不会拦截的),传递到最底层的View,就由它的onTouchEvent()方法来处理事件,若处理成功返回true,若处理失败返回false,事件依次向上传递,每一个View都调用本身的onTouchEvent()方法来处理事件,若处理成功就终止传递,若处理失败就继续向上传递。
(2)通过人为的干预,若在向下传递的过程当中被拦截了,即onInterceptTouchEvent()方法返回true,则事件将中止向下传递,直接由当前的onTouchEvent()方法来处理,若处理成功则OK,若处理不成功,则事件会向上传递。
(3)另外,dispatchTouchEvent()方法中还有“记忆”的功能,若是第一次事件向下传递到某View,它把事件继续传递交给它的子View,它会记录该事件是否被它下面的View给处理成功了,(怎么能知道呢?若是该事件会再次被向上传递到我这里来由个人onTouchEvent()来处理,那就说明下面的View都没能成功处理该事件);当第二次事件向下传递到该View,该View的dispatchTouchEvent()方法机会判断,若上次的事件由下面的view成功处理了,那么此次的事件就继续交给下面的来处理,若上次的事件没有被下面的处理成功,那么此次的事件就不会向下传递了,该View直接调用本身的onTouchEvent()方法来处理该事件。
(4)“记忆”功能的信息只在一系列事件完成以前有效,如从ACTION_DOWN事件开始,直到后续事件ACTION_MOVE,ACTION_UP结束后,“记忆”的信息就会清除。也就是说若是某View处理ACTION_DOWN事件失败了(onTouchEvent()返回false),那么后续的ACTION_MOVE,ACTION_UP等事件就不会再传递到该View了,由其父View本身来处理。在下一次发生ACTION_DOWN事件的时候,仍是会传递到该View的。
- public class MyActivity extends Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- Log.d("d", "【总统】任务<" + Util.actionToString(ev.getAction()) + "> : 须要分派");
- return super.dispatchTouchEvent(ev);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- boolean bo = false;
- Log.d("d", "【总统】任务<" + Util.actionToString(ev.getAction()) + "> : 下面都解决不了,下次不再能靠大家了,哼…只能本身尝试一下啦。能解决?" + bo);
- return bo;
- }
- }
- public class MyFrameLayout extends FrameLayout
- {
- public MyFrameLayout(Context context, AttributeSet attrs){
- super(context, attrs);
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- Log.d("d", "【省长】任务<" + Util.actionToString(ev.getAction()) + "> : 须要分派");
- return super.dispatchTouchEvent(ev);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- boolean bo = false;
- Log.d("d", "【省长】任务<" + Util.actionToString(ev.getAction()) + "> : 拦截吗?" + bo);
- return bo;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- boolean bo = false;
- Log.d("d", "【省长】任务<" + Util.actionToString(ev.getAction()) + "> : 市长是个废物,下次不再找你了,我本身来尝试一下。能解决?" + bo);
- return bo;
- }
- }
- public class MyLinearLayout extends LinearLayout{
-
- public MyLinearLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- Log.d("d", "【市长】任务<" + Util.actionToString(ev.getAction()) + "> : 须要分派");
- return super.dispatchTouchEvent(ev);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- boolean bo = false;
- Log.d("d", "【市长】任务<" + Util.actionToString(ev.getAction()) + "> : 拦截吗?" + bo);
- return bo;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- boolean bo = false;
- Log.d("d", "【市长】任务<" + Util.actionToString(ev.getAction()) + "> : 农民真没用,下次不再找你了,我本身来尝试一下。能解决?" + bo);
- return bo;
- }
- }
- public class MyTextView extends TextView
- {
- public MyTextView(Context context, AttributeSet attrs){
- super(context, attrs);
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev){
- Log.d("d", "【农民】任务<" + Util.actionToString(ev.getAction()) + "> : 须要分派,我下面没人了,怎么办?本身干吧");
- return super.dispatchTouchEvent(ev);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev){
- boolean bo = true;
- Log.d("d", "【农民】任务<" + Util.actionToString(ev.getAction()) + "> : 本身动手,埋头苦干。能解决?" + bo);
- return bo;
- }
- }