Android事件分发机制

android普通view(不包含ViewGroup)和activity中主要有一下两个方法处理事件:

publicbooleandispatchTouchEvent(MotionEventev)//分发事件publicbooleanonTouchEvent(MotionEventevent)//处理事件

ViewGroup中还一个方法:

publicbooleanonInterceptTouchEvent(MotionEventev)//拦截事件

1、activity中,顺序是:事件分发->事件处理,如果在事件分发时消费了某个事件(returntrue)则事件处理将不会接收到该事件。

publicclassMainActivityextendsActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}//事件分发@OverridepublicbooleandispatchTouchEvent(MotionEventev){if(ev.getAction()==MotionEvent.ACTION_MOVE){System.out.println("dispatchTouchEvent-->ACTION_MOVE");returntrue;//表示我消费了,不继续分发}returnsuper.dispatchTouchEvent(ev);}//处理事件@OverridepublicbooleanonTouchEvent(MotionEventevent){switch(event.getAction()){caseMotionEvent.ACTION_DOWN:System.out.println("onTouchEvent-->ACTION_DOWN");break;caseMotionEvent.ACTION_MOVE:System.out.println("onTouchEvent-->ACTION_MOVE");break;caseMotionEvent.ACTION_UP:System.out.println("onTouchEvent-->ACTION_UP");break;}returnsuper.onTouchEvent(event);}}

以上代码的结果:

onTouchEvent-->ACTION_DOWN

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

onTouchEvent-->ACTION_UP

从结果上看:ACTION_MOVE并没有到onTouchEvent中,因为我们在dispatchTouchEvent判断,如果是ACTION_MOVEreturntrue表示消耗掉该事件,事件就不会分发到onTouchEvent中,所有onTouchEvent只能接收到ACTION_DOWNACTION_UP事件。

2、普通view的事件分发

一个普通view的事件由dispatchTouchEvent分发事件,事件的顺序是ACTION_DOWNACTION_MOVEACTION_UP,如果有一个事件被消费掉,其他的事件不会执行到;分发事件由onTouch首先接收到,如果onTouch返回true了,表示消费掉了该事件,那么该viewclick事件将不会执行。

mButton.setOnTouchListener(newOnTouchListener(){@OverridepublicbooleanonTouch(Viewv,MotionEventevent){System.out.println("onTouch..."+event.getAction());returntrue;//消费了该事件,下面的click事件不会执行}});mButton.setOnClickListener(newOnClickListener(){@OverridepublicvoidonClick(Viewv){//因为上面的onTouch把事件消费了,则这里执行不到System.out.println("onClick...");}});

3、ViewGroup的事件分发:

ViewGroup的事件分发稍微麻烦点,以自定义的LinearLayout:MyLayout为例;

事件发生,首先由MyLayout的dispatchTouchEvent进行事件的分发
然后到MyLayout的onInterceptTouchEvent拦截事件
1、onInterceptTouchEvent如果return true表示拦截该事件,并在MyLayout中处理
剩下的事件,事件继续由MyLayout进行分发,分发机制同上面的view事件分发机制,但这次分发不会考虑分发给子view,也不会走onInterceptTouchEvent,因为系统已经知道
该套事件MyLayout已经拦截,所以直接在MyLayout中处理

2、如果MyLayoutonInterceptTouchEvent返回false(默认返回false[1]),表示不拦截事件,由MyLayout的子view(以Button为例)的dispatchTouchEvent开始分发事件,分发机制就是上面的view事件分发机制。

public class MyLayout extends LinearLayout {public MyLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MyLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {System.out.println("dispatchTouchEvent");return super.dispatchTouchEvent(ev);}// 事件发生, 首先由MyLayout的dispatchTouchEvent进行事件的分发// 然后到MyLayout的onInterceptTouchEvent拦截事件// 如果return true表示拦截该事件,并在MyLayout中处理// 剩下的事件继续由MyLayout进行分发,这次分发不会考虑分发给// 子view,也不会走onInterceptTouchEvent,因为系统已经知道// 该套事件MyLayout已经拦截,所以直接在MyLayout中处理// 该demo的执行结果:// 第一套down、move、up :// dispatchTouchEvent// onInterceptTouchEvent// action_down...// dispatchTouchEvent// action_move...// dispatchTouchEvent// action_move...// dispatchTouchEvent// action_move...// dispatchTouchEvent// action_up...// 再一套:// dispatchTouchEvent// onInterceptTouchEvent// action_down...// dispatchTouchEvent// action_move...// dispatchTouchEvent// action_move...// dispatchTouchEvent// action_move...// dispatchTouchEvent// action_up...@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {System.out.println("onInterceptTouchEvent");if(ev.getAction() == MotionEvent.ACTION_DOWN) {return true;}return super.onInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:System.out.println("action_down...");break;case MotionEvent.ACTION_UP:System.out.println("action_up...");break;case MotionEvent.ACTION_MOVE:System.out.println("action_move...");break;}return true;}}

执行的结果:

第一套down、move、up :
dispatchTouchEvent
onInterceptTouchEvent
action_down...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_up...

再一套:
dispatchTouchEvent
onInterceptTouchEvent
action_down...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_up...

MyLinearLayout

publicclassMyLinearLayoutextendsLinearLayout{publicMyLinearLayout(Contextcontext,AttributeSetattrs){super(context,attrs);}@OverridepublicbooleanonInterceptTouchEvent(MotionEventev){returntrue;//这里返回true,则拦截掉事件,不会再往子view传递,继续调用该view的dispachTouchEvent和onTouch}}

MainActivity:

publicclassMainActivityextendsActivity{privateMyLinearLayoutmLayout;privateButtonmButton;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mLayout=(MyLinearLayout)findViewById(R.id.layout);mButton=(Button)findViewById(R.id.click);mLayout.setOnTouchListener(newOnTouchListener(){@OverridepublicbooleanonTouch(Viewv,MotionEventevent){System.out.println("layouttouch"+event.getAction());returnfalse;}});mButton.setOnClickListener(newOnClickListener(){@OverridepublicvoidonClick(Viewv){//因为在MyLinearLayout中已经拦截了事件,所以这里不会输出System.out.println("buttonclick...");}});}}

执行结果:

layouttouch0


注意[1]:ListViewonInterceptTouchEvent默认返回的是true,表示拦截了事件。所以在listView中的Button按照普通设置click的方法是不能点击的。


更多相关文章

  1. Android ListView getView()方法重复调用导致position错位
  2. 使用反射调用android API中的hide方法
  3. Android 中使用自定义字体的方法
  4. 半透明Activity方法
  5. Android开发由eclipse转Android Studio中一些常见出错问题解决方
  6. android摄像头采集和预览-第二种方法
  7. 使用WebView中的JavaScript调用Android方法
  8. H5 Web网页通过JS(JavaScript)脚本调用Android本地原生方法函数
  9. android 静音方法

随机推荐

  1. Activity启动模式记录
  2. Android为数据存储提供几种方式
  3. Dev-Guide_Android Basics_What is Andro
  4. android sdk更新后出现please update ADT
  5. Android Permission denied 错误(附Andro
  6. Android stuio在MainActivity中运行java
  7. 【代码】android通过criteria选择合适的
  8. Android消息循环机制源码分析
  9. AndroidManifest.xml 配置文件
  10. android studio/idea各种坑