Android 事件分发机制

来源:互联网 发布:怎么在淘宝上搜115 编辑:程序博客网 时间:2024/05/17 01:11

在写自定义控件或者view的时候肯定会涉及到事件的分发,今天来记录下自己的学习经验。

首先我们要知道跟touch事件有关的方法有:

public boolean dispatchTouchEvent(MotionEvent ev);  public boolean onInterceptTouchEvent(MotionEvent ev); public boolean onTouchEvent(MotionEvent ev); 

dispatchTouchEvent()
用来分派事件。其中调用了onInterceptTouchEvent()和onTouchEvent(),一般不重写该方法。

onInterceptTouchEvent()
用来拦截事件。默认是:{return false;}表示不拦截该事件,事件将向下传递。若重写该方法,使其返回true,则表示拦截事件终止向下传递

onTouchEvent()
用来处理事件。返回true则表示该View能处理该事件,事件将被消费掉;返回false表示不能处理,则把事件继续向下分发,如果向下没有子view则向上返回上一级处理,以此类推继续返。

这里还有个 public boolean onTouch(View v, MotionEvent event) 方法要说明下:

onTouchEvent(MotionEvent ev)onTouch(View v, MotionEvent event) 都可以用来处理手势监听,他们的区别我们通过两个例子来了解:
1、

public class MyButton extends Button {      public MyButton(Context context) {          super(context);          // TODO Auto-generated constructor stub      }      public MyButton(Context context, AttributeSet attributeSet) {          super(context, attributeSet);          // TODO Auto-generated constructor stub      }      @Override      public boolean onTouchEvent(MotionEvent event) {           return super.onTouchEvent(event); ;      } 

2、

MyButton= (Button) findViewById(R.id.mybutton);        MyButton.setOnTouchListener(new OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                // TODO Auto-generated method stub                return false;            }        });

可以看到一个是在重写控件的时候重写的方法,一个是在Activity里面设置监听时调用的方法。
但是onTouchListener的onTouch方法优先级比onTouchEvent高,如果都设置的话onTouch会先触发。
假如onTouch方法返回false会接着触发onTouchEvent,反之如果返回true则onTouchEvent方法不会被调用。
诸如onclick事件的实现等等都基于onTouchEvent,假如onTouch返回true,这些事件将不会被触发。
他俩都可以监听手势操作。由于平时我们一般都会比较偏向重写onTouchEvent方法。所以这里就只拿onTouchEvent来说。

好了言归正传接着说上述三个方法,上述三个方法不同的类拥有的方法也不同:
1、Activity类拥有: dispatchTouchEvent(); onTouchEvent();
2、ViewGroup(继承自View,表示可以有子控件,如FrameLayout、Linearlayout、Listview这些): 三个方法都拥有。
3、View(普通的控件,没有子布局的,如Button、TextView): dispatchTouchEvent(); onTouchEvent();

现在用一个例子来具体说下过程:
这里写图片描述

A –> frameLayout
C –> LinearLayout
D –> TextView

现在开始点击D
图是自带的画图工具画的,希望大家凑合看下。。。
这里写图片描述

总得来说,当点击事件到底层View(一般是个ViewGroup)以后,就会调用这个ViewGroup的dispatchTouchEvent方法,如果这个ViewGroup拦截事件返回true(默认是返回false),则事件由此ViewGroup处理,如果此时ViewGroup的OnTouchListener被设置,则onTouch会被调用,否则onTouchEvent会被调用,如果都提供的话就是上面所说的onTouch优先级高会屏蔽掉onTouchEvent。反之如果ViewGroup的拦截事件返回false,则事件会传递给在他点击链上的子View,这个时候子View的dispatchTouchEvent被调用,到此为止事件就从底层View传递到它的上一层View了,接下来的和其底层View传过来的行为一致了,如此循环直到整个事件派发结束。如果一个点击事件的子View的onTouchEvent返回了false,其父的onTouchEvent也返回了false,所有的View都没去处理,则最终会由Activity来处理。

如果你看过我自定义view-SlideSwitch开源详解的就会发现public boolean onTouchEvent(MotionEvent event) 方法里面的第一句话 getParent().requestDisallowInterceptTouchEvent(true); 这句话出现的原因是当SlideSwitch放在ScrollView里面滑动的时候会和ScrollView的滑动产生冲突,所以这里我们需要在按住SlideSwitch滑动的时候屏蔽掉ScrollView的滑动。通过requestDisallowInterceptTouchEvent()我们可以对disallowIntercept的值进行修改。这里为什么这么修改,大家有兴趣可以查看下源码,这里就不给提供了。

0 0
原创粉丝点击