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简明开发教程十六:Button 画刷示例
  2. Android简明开发教程十六:Button 画刷示例
  3. Android简明开发教程十六:Button 画刷示例
  4. Android屏幕相关设置
  5. 第十周智能手机开发学习笔记
  6. android WebView总结
  7. android WebView总结
  8. android WebView总结
  9. android WebView总结

随机推荐

  1. Android传感器之光照传感器
  2. 安卓打飞机源码分享
  3. 我们团队一位Android开发者的故事
  4. android 控件 自动提示(AutoCompleteText
  5. android 自定义View轮盘抽奖
  6. [安卓教学] 创建你的第一个安卓应用 - 课
  7. onAttachedToWindow () 和 onDetachedFro
  8. AChartEngine中大饼图
  9. l-sensor 亮度传感器驱动---stk2011
  10. Android简单实现滚动悬停效果