Android 点击事件解析

来源:互联网 发布:手算工程量算法 编辑:程序博客网 时间:2024/06/05 06:18

写在前面
对Android Event事件做一个详细整理。

测试验证:
一:在Activity中只有一个View控件,给View设置了onClickListener和onTouchListener事件

        test.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Log.i("TAG","onClick");            }        });        test.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                switch (event.getAction()) {                    case MotionEvent.ACTION_DOWN:                        Log.i("TAG","onTouch  ACTION_DOWN");                        break;                    case MotionEvent.ACTION_MOVE:                        Log.i("TAG","onTouch  ACTION_MOVE");                        break;                    case MotionEvent.ACTION_UP:                        Log.i("TAG","onTouch  ACTION_UP");                        break;                }                return false;            }        });

接下来对View 进行点击测试,到底是View的点击事件先执行还是onTouch先执行:

08-05 10:07:54.010 19588-19588/com.cms.testevent I/TAG: onTouch  ACTION_DOWN08-05 10:07:54.070 19588-19588/com.cms.testevent I/TAG: onTouch  ACTION_UP08-05 10:07:54.080 19588-19588/com.cms.testevent I/TAG: onClick

这是在点击View之后马上抬起,可以看到是先执行onTouch事件之后才到onClick事件。如果在按下View的时候手指稍微移动后在立马抬起会执行Action_Move事件,如下:

08-05 10:12:03.810 19588-19588/com.cms.testevent I/TAG: onTouch  ACTION_DOWN08-05 10:12:03.860 19588-19588/com.cms.testevent I/TAG: onTouch  ACTION_MOVE08-05 10:12:03.870 19588-19588/com.cms.testevent I/TAG: onTouch  ACTION_UP08-05 10:12:03.870 19588-19588/com.cms.testevent I/TAG: onClick

注意到onTouch有返回值,默认返回false,那这个返回值有什么影响呢?我们进行测试:

08-05 10:19:06.290 5068-5068/com.cms.testevent I/TAG: onTouch  ACTION_DOWN08-05 10:19:06.390 5068-5068/com.cms.testevent I/TAG: onTouch  ACTION_MOVE08-05 10:19:06.400 5068-5068/com.cms.testevent I/TAG: onTouch  ACTION_MOVE08-05 10:19:06.410 5068-5068/com.cms.testevent I/TAG: onTouch  ACTION_UP

测试发现onClick不在执行了,那这又是怎么回事呢?我们从源码中去寻找答案,找到View的dispatchTouchEvent方法。

    public boolean dispatchTouchEvent(MotionEvent event) {        ....        if (onFilterTouchEventForSecurity(event)) {            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {                result = true;            }            //noinspection SimplifiableIfStatement            ListenerInfo li = mListenerInfo;            if (li != null && li.mOnTouchListener != null                    && (mViewFlags & ENABLED_MASK) == ENABLED                    && li.mOnTouchListener.onTouch(this, event)) {                result = true;            }            if (!result && onTouchEvent(event)) {                result = true;            }        }        ....        return result;    }

看关键代码,在第10行到14行,判断了li是否为空和li.onTouchListener是否为空,这个onTouchListener是什么呢?找到onTouchListerner发现就是前面设置的setOnTouchListener()

    public void setOnTouchListener(OnTouchListener l) {        getListenerInfo().mOnTouchListener = l;    }

之后在判断View是否是Enable的,默认是Enable的,然后调用了onTouchListener的onTouch方法,如果返回true,那么4个条件全部满足,result为true,如果result为true那么接下来的onTouchEvent方法也就不在执行了,这也就验证了为什么onTouch返回true onClick事件就不在执行的原因。

接下来我们看下onTouchEvent的源码,只有在View是可点击的情况下才会执行事件,前面设置了setOnClickListener所以会执行点击事件,点击事件是在performClick()里面执行的。

public boolean onTouchEvent(MotionEvent event) {       ....        if (((viewFlags & CLICKABLE) == CLICKABLE ||                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||                (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {            switch (action) {                case MotionEvent.ACTION_UP:                    ...                             if (!focusTaken) {                                // Use a Runnable and post this rather than calling                                // performClick directly. This lets other visual state                                // of the view update before click actions start.                                if (mPerformClick == null) {                                    mPerformClick = new PerformClick();                                }                                if (!post(mPerformClick)) {                                    performClick();                                }                            }                    ...                    break;                case MotionEvent.ACTION_DOWN:                    ...                    break;                case MotionEvent.ACTION_CANCEL:                    ...                    break;                case MotionEvent.ACTION_MOVE:            ...                    break;            }            return true;        }        return false;    }

点击事件在performClick()里被执行。

    public boolean performClick() {        final boolean result;        final ListenerInfo li = mListenerInfo;        if (li != null && li.mOnClickListener != null) {            playSoundEffect(SoundEffectConstants.CLICK);            li.mOnClickListener.onClick(this);            result = true;        } else {            result = false;        }        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);        return result;    }

关于点击事件这一块先说到这里。

原创粉丝点击