【Android】View的事件分发机制123

来源:互联网 发布:电力线路设计软件 编辑:程序博客网 时间:2024/06/14 18:24

1.通过日志来分析事件传递相关方法的执行流程

为了更好的了解view的事件传递,我们可以自定义一个button继承自Button,并重写事件传递相关方法通过打日志来分析各个方法的执行顺序。
自定义button,重写dispatchTouchEvent和onTouchEvent
public class MyButton extends Button {    public MyButton(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean dispatchTouchEvent(MotionEvent event) {        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.d("dispatchTouchEvent", "ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.d("dispatchTouchEvent", "ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.d("dispatchTouchEvent", "ACTION_UP");                break;        }        return super.dispatchTouchEvent(event);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.d("onTouchEvent", "ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.d("onTouchEvent", "ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.d("onTouchEvent", "ACTION_UP");                break;        }        return super.onTouchEvent(event);    }}
将自定义button添加到布局中
<LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.tfx.test.MainActivity">    <com.tfx.test.MyButton        android:id="@+id/bt"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="button"/></LinearLayout>
MainActivity代码,给自定义button注册setOnTouchEvent监听
public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Button button = (Button) findViewById(R.id.bt);        button.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View view, MotionEvent motionEvent) {                switch (motionEvent.getAction()) {                    case MotionEvent.ACTION_DOWN:                        Log.d("onTouch", "ACTION_DOWN");                        break;                    case MotionEvent.ACTION_MOVE:                        Log.d("onTouch", "ACTION_MOVE");                        break;                    case MotionEvent.ACTION_UP:                        Log.d("onTouch", "ACTION_UP");                        break;                }                return false;            }        });    }}
重写了三个事件分发相关方法后,运行demo并单击button按钮,然后看输出的日志
12-19 09:22:56.478 1837-1837/com.tfx.test D/dispatchTouchEvent: ACTION_DOWN12-19 09:22:56.478 1837-1837/com.tfx.test D/onTouch: ACTION_DOWN12-19 09:22:56.478 1837-1837/com.tfx.test D/onTouchEvent: ACTION_DOWN12-19 09:22:56.556 1837-1837/com.tfx.test D/dispatchTouchEvent: ACTION_UP12-19 09:22:56.556 1837-1837/com.tfx.test D/onTouch: ACTION_UP12-19 09:22:56.556 1837-1837/com.tfx.test D/onTouchEvent: ACTION_UP
如果点击按钮时手指稍微蹭一下,会执行多次move,如下
12-19 09:20:17.253 1837-1837/com.tfx.test D/dispatchTouchEvent: ACTION_DOWN12-19 09:20:17.253 1837-1837/com.tfx.test D/onTouch: ACTION_DOWN12-19 09:20:17.253 1837-1837/com.tfx.test D/onTouchEvent: ACTION_DOWN12-19 09:20:17.295 1837-1837/com.tfx.test D/dispatchTouchEvent: ACTION_MOVE12-19 09:20:17.296 1837-1837/com.tfx.test D/onTouch: ACTION_MOVE12-19 09:20:17.296 1837-1837/com.tfx.test D/onTouchEvent: ACTION_MOVE12-19 09:20:17.463 1837-1837/com.tfx.test D/dispatchTouchEvent: ACTION_MOVE12-19 09:20:17.463 1837-1837/com.tfx.test D/onTouch: ACTION_MOVE12-19 09:20:17.463 1837-1837/com.tfx.test D/onTouchEvent: ACTION_MOVE12-19 09:20:17.580 1837-1837/com.tfx.test D/dispatchTouchEvent: ACTION_MOVE12-19 09:20:17.580 1837-1837/com.tfx.test D/onTouch: ACTION_MOVE12-19 09:20:17.580 1837-1837/com.tfx.test D/onTouchEvent: ACTION_MOVE12-19 09:20:17.716 1837-1837/com.tfx.test D/dispatchTouchEvent: ACTION_UP12-19 09:20:17.717 1837-1837/com.tfx.test D/onTouch: ACTION_UP12-19 09:20:17.717 1837-1837/com.tfx.test D/onTouchEvent: ACTION_UP
从日志我们大致可以看出,不管是down、move、up执行的流程都是dispatchTouchEvent --> onTouch --> onTouchEvent。
onTouchListener的onTouch方法是有返回值的,如果把返回值改为return true再运行,会发现onTouchEvent方法得不到执行,这是为什么呢?此时若再给按钮注册单击事件,会发现单击事件也不会被触发,这又是为什么呢? 带着这两个问题,接下来我们对dispatchTouchEvent方法进行分析。

2.dispatchTouchEvent方法

进入button的父类TextView我们并没有发现该方法,继续在它的父类view里面找,此时就能看到dispatchTouchEvent方法的源码,如下:
public boolean dispatchTouchEvent(MotionEvent event) {  if (!onFilterTouchEventForSecurity(event)) {  return false;  }  if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&  mOnTouchListener.onTouch(this, event)) {  return true;  }  return onTouchEvent(event);  }
主要就看第二个if语句,这里会有三个条件:
条件一:对mOnTouchListener进行非空判断,也就是判断是否注册了onTouchListener监听
条件二:判断view是否是enable,一般控件默认都是enable
条件三:判断onTouchEvent的onTouch方法是否返回true
如果这三个条件都成立,那么dispatchTouchEvent方法就返回true,否则执行onTouchEvent并返回。
接着说上面的第一个问题,当三个条件都满足了,dispatchTouchEvent方法就会返回ture,onTouchEvent方法将得不到执行,也就是说onTouchListener的onTouch方法的返回值决定了onTouchEvent方法能否得到执行,如果返回true事件将会被消费,不再继续传递给onTouchEvent方法,默认返回false,onTouchEvent方法将得到执行,到这里第一个问题就解决了。
接着说问题二,根据问题一,我们可以断定单击事件的onClick方法是在onTouchEvent方法中执行的,只有onTouchEvent方法得到执行,才能响应单击事件。还有onTouch方法的执行优先于onClick方法,onTouch方法做的比onClick更多,能响应dowm、move、up多个手势。

3.onTouchEvent方法

111



0 0
原创粉丝点击