最新消息:文章中包含代码时,请遵守代码高亮规范!

View的事件分发机制【原创】

Android 王 伟 156浏览 0评论

view的事件分发主要依靠的是Android中的MotionEvent类。事件分发就是对 MotionEvent事件分发的过程。分发过程主要是由三个方法共同完成的:dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent。先分别介绍一下这三个方法。

public boolean dispatchTouchEvent(MotionEvent ev)

这个方法从取名上就可以看出来是分发事件的意思。如果事件能传递给当前的View时,该方法一定会被调用。返回结果受当前View的onTouchEvent和下级的dispatchTouchEvent方法影响,表示是否消耗当前的事件。

public boolean onInterceptTouchEvent(MotionEvent ev)

该方法从取名上也可以知道是阻止触摸事件的意思。其实就是是否拦截某个事件的意思。如果当前View拦截了某个事件,那么在同一个事件序列中,此方法就不会再次被调用。返回的结果表示是否拦截当前事件。

public boolean onTouchEvent(MotionEvent ev)

此方法实在dispatchTouchEvent方法中调用,用来处理事件的。返回结果表示是否消耗当前事件。如果不消耗,同一个事件序列,当前View无法再次接受事件。

以上是对三个方法的介绍,从这三个方法中可以看出来View的事件分发,有三个阶段:分发,拦截,消费。下面说一下触摸事件对应的MotionEvent类。它的类型主要分为 三种:ACTION_DOWN、ACTION_MOVE、ACTION_UP。

  • ACTION_DOWN:用户手指的按下操作,一个按下操作意味着一次触摸事件的开始。
  • ACTION_MOVE:用户手指按压屏幕后,在松开之前,如果移动的距离超过一定的值,那么会被判定为ACTION_MOVE操作,一般情况下,手指的轻微一定都会触发一系列的移动事件。
  • ACTION_UP:用户手指离开屏幕的操作,一次抬起操作标志一次触摸事件的结束。

View在Android中只拥有dispatchTouchEvent和onTouchEvent两个方法。ViewGroup是View的子类。但是这里所指的View是指除ViewGroup外的View控件。

举例说明一下:

新建一个工程,先写个MyTextView继承AppCompatTextView,代码如下:

public class MyTextView extends AppCompatTextView {

    private static final String TAG = "MyTextView";

    public MyTextView(Context context) {
        super(context);
    }

    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.i(TAG, "dispatchTouchEvent   ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i(TAG, "dispatchTouchEvent   ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i(TAG, "dispatchTouchEvent   ACTION_UP");
                break;
            default:
                break;
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.i(TAG, "onTouchEvent   ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i(TAG, "onTouchEvent   ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i(TAG, "onTouchEvent   ACTION_UP");
                break;
            default:
                break;
        }
        return super.onTouchEvent(event);
    }
}

接着修改一下布局文件,将TextView修改为MyTextView,然后修改MainActivity,代码如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener, View.OnTouchListener {
    private static final String TAG = "MainActivity";
    private MyTextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (MyTextView) findViewById(R.id.textView);
        mTextView.setOnClickListener(this);
        mTextView.setOnTouchListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.textView:
                Log.i(TAG, "MyTextView onclick");
                break;
            default:
                break;
        }
    }

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        switch (view.getId()) {
            case R.id.textView:
                switch (motionEvent.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        Log.i(TAG, "MyTextView  onTouch   ACTION_DOWN");
                        break;
                    case MotionEvent.ACTION_MOVE:
                        Log.i(TAG, "MyTextView  onTouch   ACTION_MOVE");
                        break;
                    case MotionEvent.ACTION_UP:
                        Log.i(TAG, "MyTextView  onTouch   ACTION_UP");
                        break;
                    default:
                        break;
                }
                break;
            default:
                break;
        }
        return false;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.i(TAG, "dispatchTouchEvent   ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i(TAG, "dispatchTouchEvent   ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i(TAG, "dispatchTouchEvent   ACTION_UP");
                break;
            default:
                break;
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.i(TAG, "onTouchEvent   ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i(TAG, "onTouchEvent   ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i(TAG, "onTouchEvent   ACTION_UP");
                break;
            default:
                break;
        }
        return super.onTouchEvent(event);
    }
}

运行项目,查看log:

com.bob.viewtestdemo I/MainActivity: dispatchTouchEvent ACTION_DOWN
com.bob.viewtestdemo I/MyTextView: dispatchTouchEvent ACTION_DOWN
com.bob.viewtestdemo I/MainActivity: MyTextView onTouch ACTION_DOWN
com.bob.viewtestdemo I/MyTextView: onTouchEvent ACTION_DOWN
com.bob.viewtestdemo I/MainActivity: dispatchTouchEvent ACTION_MOVE
com.bob.viewtestdemo I/MyTextView: dispatchTouchEvent ACTION_MOVE
com.bob.viewtestdemo I/MainActivity: MyTextView onTouch ACTION_MOVE
com.bob.viewtestdemo I/MyTextView: onTouchEvent ACTION_MOVE
com.bob.viewtestdemo I/MainActivity: dispatchTouchEvent ACTION_MOVE
com.bob.viewtestdemo I/MyTextView: dispatchTouchEvent ACTION_MOVE
com.bob.viewtestdemo I/MainActivity: MyTextView onTouch ACTION_MOVE
com.bob.viewtestdemo I/MyTextView: onTouchEvent ACTION_MOVE
com.bob.viewtestdemo I/MainActivity: dispatchTouchEvent ACTION_MOVE
com.bob.viewtestdemo I/MyTextView: dispatchTouchEvent ACTION_MOVE
com.bob.viewtestdemo I/MainActivity: MyTextView onTouch ACTION_MOVE
com.bob.viewtestdemo I/MyTextView: onTouchEvent ACTION_MOVE
com.bob.viewtestdemo I/MainActivity: dispatchTouchEvent ACTION_UP
com.bob.viewtestdemo I/MyTextView: dispatchTouchEvent ACTION_UP
com.bob.viewtestdemo I/MainActivity: MyTextView onTouch ACTION_UP
com.bob.viewtestdemo I/MyTextView: onTouchEvent ACTION_UP
com.bob.viewtestdemo I/MainActivity: MyTextView onclick

总结一下,

  • 用户点击屏幕ACTION_DOWN执行MainActivity的dispatchTouchEvent,看返回值,如果是super方法,执行MyTextView的dispatchTouchEvent;如果返回的是true或者是false,将不再继续分发ACTION_DOWN事件,同时不会调用 MainActivity的MyTextView onclick。
  • 执行MyTextView的dispatchTouchEvent,看返回值,如果是super方法,执行MainActivity的MyTextView onTouch;如果返回的是true或者false,当返回的是true时,将不再继续分发ACTION_DOWN事件,同时不会调用 MainActivity的MyTextView onclick,当返回的是false时,执行MainActivity的onTouchEvent。
  • 执行MainActivity的MyTextView onTouch,返回值为true时,将不再继续分发ACTION_DOWN事件,同时不会调用 MainActivity的MyTextView onclick,返回值为false时,执行MyTextView的onTouchEvent。
  • 执行MyTextView的onTouchEvent。看返回值,如果返回值是super方法,ACTION_DOWN传递完成,如返回值是true或false,当返回值为true时,ACTION_DOWN传递完成,当返回值为false时,执行MainActivity的onTouchEvent。
  • 执行MainActivity的onTouchEvent,代表ACTION_DOWN传递完成。

转载时请注明出处及相应链接,本文永久地址:https://blog.yayuanzi.com/25097.html


pay_weixin
pay_weixin
微信打赏
pay_weixin
支付宝打赏
感谢您对作者Bob的打赏,我们会更加努力!    如果您想成为作者,请点我

您必须 登录 才能发表评论!