前言ide
Android中关于触摸事件的分发传递是一个很值得研究的东西。曾不见你引入了一个ListView的滑动功能,ListView就不听你手指的指唤来滚动了;也不知道为啥Button设置了onClick和onTouch,其中谁会先响应;或许你会问onTouch和onTouchEvent有什么区别,又该如何使用?这里一切的一切,只要你了解了事件分发机制,你会发现,解释这都不是事儿!工具
相关Touch事件的方法spa
一、public boolean dispatchTouchEvent(MotionEvent ev) ————事件分发方法,分发Event所调用3d
二、public boolean onInterceptTouchEvent(MotionEvent ev) ————事件拦截方法,拦截Event所调用code
三、public boolean onTouchEvent(MotionEvent event) ————事件响应方法,处理Event所调用blog
拥有上述事件的类继承
一、Activity类(Activity及其各类继承子类)事件
dispatchTouchEvent()、onTouchEvent()get
二、ViewGroup类(LinearLayout、FrameLayout、ListView等.....)博客
dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent()
三、View类(Button、TextView等.....)
dispatchTouchEvent()、onTouchEvent()
PS:须要特别注意一点就是ViewGroup中额外拥有onInterceptTouchEvent()方法,其余两个方法为这三种类所共同拥有。
方法的简单用途解析
咱们能够发现这三个方法的返回值都为boolean类型,其实它们就是经过返回值来决定下一步的传递处理方向。
一、dispatchTouchEvent() ——用来分发事件所用
该方法会将根元素的事件自上而下依次分发到内层子元素中,直到被终止或者到达最里层元素,该方法也是采用一种隧道方式来分发。在其中会调用onInterceptTouchEvent()和onTouchEvent(),通常不会去重写。
返回false则不拦截继续往下分发,若是返回true则拦截住该事件不在向下层元素分发,在dispatchTouchEvent()方法中默认返回false。
二、onInterceptTouchEvent() ——用来拦截事件所用
该方法在ViewGroup源代码中实现就是返回false不拦截事件,Touch事件就会往下传递给其子View。
若是咱们重写该方法而且将其返回true,该事件将会被拦截,而且被当前ViewGroup处理,调用该类的onTouchEvent()方法。
三、onTouchEvent() ——用来处理事件
返回true则表示该View能处理该事件,事件将终止向上传递(传递给其父View)
返回false表示不能处理,则把事件传递给其父View的onTouchEvent()方法来处理
实战演练
好了,基础知识讲完了,上面的东西看不懂没关系,如今要睁大眼睛好好看了,由于下面开始用例子讲解Touch的事件分发机制,相信能让你们更好的理解这个分发机制。
在这个例子中,咱们须要重写四个类:
一、老板 ——> MyActivity
二、经理 ——> FrameLayout
三、组长 ——> LineaLayout
四、员工 ——> TextView
软件界面图以下:
【搞个通俗易懂的例子开开头】
一、按常理,领导都会把任务向下分派,一旦下面的人把事情作很差,就不会再把后续的任务交给下面的人来作了,只能本身亲自作,若是本身也作不了,就只能告诉上级不能完成任务,上级又会重复他的过程。
二、另外,领导都有权利拦截任务,对下级隐瞒该任务,而直接本身去作,若是作不成,也只能向上级报告不能完成任务。
流程演示
【1】、咱们假设员工能力不足,也就是将TextView的onTouchEvent()方法设置返回false,表示其不能消费该事件。
事件传递的流程:
【2】、咱们假设员工能处理该事件,也就是将TextView的onTouchEvent()方法设置返回true,表示其能处理该事件。
事件传递的流程:
【3】、咱们假设员工和组长能力不足,即TextView和LinearLayout的onTouch()返回false,可是经理解决了该问题,即FrameLayout的onTouch()返回true
事件传递的流程:
【4】假设咱们的组长在事件分发到他那里的时候,决定拦截下来不交给下面的员工,也就是onInterceptTouchEvent()返回为true,而且他也成功完成了任务,即onTouchEvent()返回值为true。
事件传递的流程:
作个小结
一、很明显,这些流程就是dispatchTouchEvent()的处理结果,可是前提是咱们不去彻底的从新实现这个方法,也就是保证须要return super.dispatchTouchEvent(ev);来肯定父类的方法有被调用。而这些事件将会由上而下的逐层传递,直到传递到最底层的View元素,此时将会调用该View的onTouchEvent()方法来处理该事件;返回true来表示对该事件已经成功处理,若是返回false则并无成功处理事件,将会把事件逐层向上传递,交给上层View的onTouchEvent()方法处理,以此类推,直至某一View成功处理该事件,或者到顶层View处理仍然返回false则放弃对该事件处理,事件消失。
二、若是在事件向下传递的过程当中,被中途拦截,也就是View的onInterceptTouchEvent()方法返回true,那么该事件将中止向下传递,并交给该层的onTouchEvent()方法处理,不管处理成功与否,底层View将不再会接收到该事件。PS:若处理失败,则会交由上层View的onTouchEvent()方法处理。
三、dispatchTouchEvent()具备记忆的功能,若是第一次事件向下传递到某View,它把事件继续传递交给它的子View,它会记录该事件是否被它下面的View给处理成功了,(怎么能知道呢?若是该事件会再次被向上传递到我这里来由个人onTouchEvent()来处理,那就说明下面的View都没能成功处理该事件);当第二次事件向下传递到该View,该View的dispatchTouchEvent()方法机会判断,若上次的事件由下面的view成功处理了,那么此次的事件就继续交给下面的来处理,若上次的事件没有被下面的处理成功,那么此次的事件就不会向下传递了,该View直接调用本身的onTouchEvent()方法来处理该事件。
四、记忆功能的信息只在一系列事件完成以前有效,如从ACTION_DOWN事件开始,直到后续事件ACTION_MOVE,ACTION_UP结束后,“记忆”的信息就会清除。也就是说若是某View处理ACTION_DOWN事件失败了(onTouchEvent()返回false),那么后续的ACTION_MOVE,ACTION_UP等事件就不会再传递到该View了,由其父View本身来处理。在下一次发生ACTION_DOWN事件的时候,仍是会传递到该View的。
附带代码
一、MyActivity
public class MyActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i("test", "【老板】下达任务:" + Util.actionToString(ev.getAction()) + ",找我的帮我完成,任务往下分发。"); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { boolean relust = false; Log.i("test", "【老板】完成任务:" + Util.actionToString(event.getAction()) + ",【经理】太差劲了,之后再也不找你干活了,我自来搞定!是否解决:" + Util.canDoTaskTop(relust)); return relust; } }
二、MyFrameLayout:
public class MyFrameLayout extends FrameLayout { public MyFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i("test", "【经理】下达任务:" + Util.actionToString(ev.getAction()) + ",找我的帮我完成,任务往下分发。"); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean relust = false; Log.i("test", "【经理】是否拦截任务:" + Util.actionToString(ev.getAction()) + ",拦下来?" + relust); return relust; } @Override public boolean onTouchEvent(MotionEvent event) { boolean relust = true; Log.i("test", "【经理】完成任务:" + Util.actionToString(event.getAction()) + ",【组长】太差劲了,之后再也不找你干活了,我自来搞定!是否解决:" + Util.canDoTask(relust)); return relust; } }
三、MyLinearLayout
public class MyLinearLayout extends LinearLayout { public MyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i("test", "【组长】下达任务:" + Util.actionToString(ev.getAction()) + ",找我的帮我完成,任务往下分发。"); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean relust = true; Log.i("test", "【组长】是否拦截任务:" + Util.actionToString(ev.getAction()) + ",拦下来?" + relust); return relust; } @Override public boolean onTouchEvent(MotionEvent event) { boolean relust = true; Log.i("test", "【组长】完成任务:" + Util.actionToString(event.getAction()) + ",【员工】太差劲了,之后再也不找你干活了,我自来搞定!是否解决:" + Util.canDoTask(relust)); return relust; } }
四、MyTextView
public class MyTextView extends TextView { public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.i("test", "【员工】下达任务:" + Util.actionToString(event.getAction()) + ",我没手下了,唉~本身干吧"); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { boolean relust = false; Log.i("test", "【员工】完成任务:" + Util.actionToString(event.getAction()) + ",【员工】如今只能靠本身了!是否解决:" + Util.canDoTask(relust)); return relust; } }
五、Util(工具类)
public class Util { public static String actionToString(int action){ String result = null; switch(action){ case MotionEvent.ACTION_DOWN: result = "ACTION_DOWN"; break; case MotionEvent.ACTION_MOVE: result = "ACTION_MOVE"; break; case MotionEvent.ACTION_UP: result = "ACTION_UP"; break; } return result; } public static String canDoTask(boolean can){ String result = null; if(can){ result = "完美解决该任务!"; } else{ result = "这活搞不定,交给老大完成吧。"; } return result; } public static String canDoTaskTop(boolean can){ String result = null; if(can){ result = "完美解决该任务!"; } else{ result = "这活搞不定,放弃该任务。"; } return result; } }
做者:enjoy风铃
出处:http://www.cnblogs.com/net168/
本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然下次不给你转载了