对于一个Android开发者来说View事件分发机制是不得不了解的.不了解事件分发机制的话很多自定义控件都无法写出来.今天我们一起来看看View的事件分发机制是如何实现的.

       首先来看个栗子:

自定义一个MyButton继承Button并重写dispatchTouchEvent和onTouchEvent方法

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

xml里面调用 

    
        MyButton mButton= (MyButton) findViewById(R.id.my_bt);        mButton.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                switch (event.getAction()) {                    case MotionEvent.ACTION_DOWN:                        Log.e(TAG, "onTouch ACTION_DOWN");                        break;                    case MotionEvent.ACTION_MOVE:                        Log.e(TAG, "onTouch ACTION_MOVE");                        break;                    case MotionEvent.ACTION_UP:                        Log.e(TAG, "onTouch ACTION_UP");                        break;                }                return false;            }        });        mButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Log.e(TAG, "onClick");            }        });        mButton.setOnLongClickListener(new View.OnLongClickListener() {            @Override            public boolean onLongClick(View v) {                Log.e(TAG, "onLongClick");                return false;            }        });

当我们只点击一下的时候日志打出

08-14 11:47:38.173 15712-15712/fun.hxy.com.testalg E/MyButton: dispatchTouchEvent ACTION_DOWN08-14 11:47:38.173 15712-15712/fun.hxy.com.testalg E/MainActivity: onTouch ACTION_DOWN08-14 11:47:38.174 15712-15712/fun.hxy.com.testalg E/MyButton: onTouchEvent ACTION_DOWN08-14 11:47:38.199 15712-15712/fun.hxy.com.testalg E/MyButton: dispatchTouchEvent ACTION_UP08-14 11:47:38.199 15712-15712/fun.hxy.com.testalg E/MainActivity: onTouch ACTION_UP08-14 11:47:38.199 15712-15712/fun.hxy.com.testalg E/MyButton: onTouchEvent ACTION_UP08-14 11:47:38.200 15712-15712/fun.hxy.com.testalg E/MainActivity: onClick

我们发现时间都是从dispatchTouchEvent开始的然后onTouch->onTouchEvent->onClick

为什么会这样呢?我们来看一下View的源码:

public boolean dispatchTouchEvent(MotionEvent event) {1      ....2       if (li != null && li.mOnTouchListener != null                    && (mViewFlags & ENABLED_MASK) == ENABLED                    && li.mOnTouchListener.onTouch(this, event)) {                result = true;            }3            if (!result && onTouchEvent(event)) {                result = true;            }               .....        return result;    }

在View的dispatchTouchEvent里面我们可以发现View先判断li.mOnTouchListener.onTouch(this, event)先执行了onTouch()事件在到第三行的onTouchEvent(),并且如果onTouch()的返回值返回了true的话就不会在往下执行onTouchEvent()方法了;

我们在看看onTouchEvent()的源码:

public boolean onTouchEvent(MotionEvent event) {                ......            switch (action) {                case MotionEvent.ACTION_UP:                     if (!focusTaken) {                                                  if (!post(mPerformClick)) {                             performClick();                         }                     }                                          break;                       }            return true;        }        return false;    }

我们发现onClick的方法是在onTouch()方法的up里面执行的.这就是为什么View点击的时候会先调用onTouch()  -> onTouchEvent() -> onClick(),面试的时候经常会问到

 

我们在来看一下长按事件:

现在我们长按button按钮

08-14 14:16:16.725 11084-11084/fun.hxy.com.testalg E/MyButton: dispatchTouchEvent ACTION_DOWN08-14 14:16:16.726 11084-11084/fun.hxy.com.testalg E/MainActivity: onTouch ACTION_DOWN08-14 14:16:16.726 11084-11084/fun.hxy.com.testalg E/MyButton: onTouchEvent ACTION_DOWN08-14 14:16:16.875 11084-11084/fun.hxy.com.testalg E/MyButton: dispatchTouchEvent ACTION_MOVE08-14 14:16:16.875 11084-11084/fun.hxy.com.testalg E/MainActivity: onTouch ACTION_MOVE08-14 14:16:16.875 11084-11084/fun.hxy.com.testalg E/MyButton: onTouchEvent ACTION_MOVE08-14 14:16:16.890 11084-11084/fun.hxy.com.testalg E/MyButton: dispatchTouchEvent ACTION_MOVE08-14 14:16:16.890 11084-11084/fun.hxy.com.testalg E/MainActivity: onTouch ACTION_MOVE08-14 14:16:16.890 11084-11084/fun.hxy.com.testalg E/MyButton: onTouchEvent ACTION_MOVE08-14 14:16:16.906 11084-11084/fun.hxy.com.testalg E/MyButton: dispatchTouchEvent ACTION_MOVE......08-14 14:16:17.142 11084-11084/fun.hxy.com.testalg E/MainActivity: onLongClick08-14 14:16:17.189 11084-11084/fun.hxy.com.testalg E/MyButton: dispatchTouchEvent ACTION_MOVE08-14 14:16:17.190 11084-11084/fun.hxy.com.testalg E/MainActivity: onTouch ACTION_MOVE08-14 14:16:17.190 11084-11084/fun.hxy.com.testalg E/MyButton: onTouchEvent ACTION_MOVE.....08-14 14:16:17.948 11084-11084/fun.hxy.com.testalg E/MyButton: dispatchTouchEvent ACTION_UP08-14 14:16:17.949 11084-11084/fun.hxy.com.testalg E/MainActivity: onTouch ACTION_UP08-14 14:16:17.949 11084-11084/fun.hxy.com.testalg E/MyButton: onTouchEvent ACTION_UP08-14 14:16:17.954 11084-11084/fun.hxy.com.testalg E/MainActivity: onClick

我们发现长按的时候会执行ACTION_DOWN因为手指按住可能会有一点抖,会执行不等次的ACTION_MOVE,然后先执行onLongClick后面放手在执行onClick.

再次翻看onTouchEvent()的源码:

public boolean onTouchEvent(MotionEvent event) {        switch (action) {            case MotionEvent.ACTION_UP:                ......                                if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {                    if (!post(mPerformClick)) {                        performClick();                    }                }                ......                break;            case MotionEvent.ACTION_DOWN:                ......                checkForLongClick(0, x, y);                ......                break;        }        return false;    }

我们发现在ACTION_DOWN的时候,系统就会执行checkForLongClick方法

private void checkForLongClick(int delayOffset, float x, float y) {        if (mPendingCheckForLongPress == null) {                mPendingCheckForLongPress = new CheckForLongPress();            }            postDelayed(mPendingCheckForLongPress,                    ViewConfiguration.getLongPressTimeout() - delayOffset);            }

这个checkForLongClick里面执行了一个延迟操作延迟五百毫秒时候就会执行CheckForLongPress这个延迟事件

@Override        public void run() {            if (isPressed() && (mParent != null)                    && mOriginalWindowAttachCount == mWindowAttachCount) {                if (performLongClick(mX, mY)) {                    mHasPerformedLongPress = true;                }            }        }

这个方法里执行了

    public boolean performLongClick(float x, float y) {        mLongClickX = x;        mLongClickY = y;        final boolean handled = performLongClick();        mLongClickX = Float.NaN;        mLongClickY = Float.NaN;        return handled;    }

我们可以看到performLongClick这个方法的返回值为boolean类型,所以当onLongClickListener方法返回值改为true的时候,mHasPerformedLongPress 被置为true,从上面又可以看到只有在mHasPerformedLongPress为false的时候performClick()方法才会执行.

好了,到这里View的事件机制差不多就看完一遍了,View的事件机制还是比较简单的,下一篇我将跟大家一起学习一下ViewGroup的事件机制.希望大家都能有所收获.

更多相关文章

  1. android 执行monkey指令的方法
  2. Android(安卓)音乐播放器
  3. Android(安卓)中onSaveInstanceState()解析
  4. Android一些基础面试题
  5. EventBus源码追踪
  6. 学习笔记_android四种点击事件方法
  7. Android中父View和子view的点击事件
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. tab2
  2. Web初试
  3. Android(安卓)使用Camera 打开预览Demo
  4. android的http工具类
  5. Android(安卓)activity的回传数据
  6. SD卡文件列表
  7. Android(安卓)Multiple dex files define
  8. Android(安卓)接收蓝牙耳机按键操作
  9. Android(安卓)Studio Interface一例
  10. Android(安卓)Studio Property属性动画