【android】深入理解view中用户事件处理机制

onTouch和onClick

程序中一般会使用onTouch事件和onClick事件来处理用户行为触发的代码

XXX.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
            	Log.i("ceshi","onTouch");
                return false;
            }
        });
XXX.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
				Log.i("ceshi","onClick");
            }
        });

用户点击,首先触发onTouch事件,然后执行onClick事件,但是当onTouch事件返回值设置为true时,事件就被拦截了,onClick事件就不再执行
为什么返回true就不再执行,就需要说到另一个方法dispatchTouchEvent

dispatchTouchEvent

dispatchTouchEvent是用户事件触发的入口,页面控件被用户点击后,系统会触发dispatchTouchEvent方法,该方法大致执行代码如下:

    public boolean dispatchTouchEvent(MotionEvent event) {
        boolean result = false;

        // 如果mOnTouchListener不为空,且控件处于可控状态,就执行onTouch
        if (li != null && li.mOnTouchListener != null
                && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnTouchListener.onTouch(this, event)) {
            result = true;
        }
        // 如果mOnTouchListener为空,或控件不可控,或onTouch返回false,就执行onTouchEvent
        if (!result && onTouchEvent(event)) {
            result = true;
        }

        return result;
    }

执行了如下逻辑判断:
1.判断onTouchListener是否不为空,控件是否可控
2.如果都满足,执行onTouchListener的onTouch方法
3.根据onTouch方法的返回值,决定是否执行onTouchEvent方法
4.如果onTouch返回值是false,执行onTouchEvent

综上,onTouch返回false,执行onTouchEvent。onClick在哪呢,就要去onTouchEvent中看看了

onTouchEvent

该方法大致执行代码如下,次要代码已删减:

    public boolean onTouchEvent(MotionEvent event) {
        final int viewFlags = mViewFlags;
        final int action = event.getAction();
        final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
                || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
                || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
        if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
            switch (action) {
                case MotionEvent.ACTION_UP:
                    if (!focusTaken) {
                        if (mPerformClick == null) {
                            mPerformClick = new PerformClick();
                        }
                        if (!post(mPerformClick)) {
                            performClickInternal();
                        }
                    }
                    break;
                case MotionEvent.ACTION_DOWN:
                    
                    break;

                case MotionEvent.ACTION_CANCEL:
                    
                    break;

                case MotionEvent.ACTION_MOVE:
                   
                    break;
            }
            return true;
        }
        return false;
    }

可以看到,经过一系列的判断后,最终执行了performClickInternal方法,我们再去performClickInternal方法中看看

    private boolean performClickInternal() {
        // Must notify autofill manager before performing the click actions to avoid scenarios where
        // the app has a click listener that changes the state of views the autofill service might
        // be interested on.
        notifyAutofillManagerOnClick();

        return performClick();
    }

可以发现performClickInternal方法中执行了performClick,继续深入

    public boolean performClick() {
        // We still need to call this method to handle the cases where performClick() was called
        // externally, instead of through performClickInternal()
        notifyAutofillManagerOnClick();

        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);

        notifyEnterOrExitForAutoFillIfNeeded(true);

        return result;
    }

找到这里,终于发现了OnClickListener.onClick。

总结,整体执行流程如下:
1、用户点击页面控件→执行dispatchTouchEvent
2、dispatchTouchEvent中执行OnTouchListener的onTouch方法
3、如果onTouch返回值为false→执行onTouchEvent
4、执行onTouchEvent中的performClickInternal方法
5、执行performClickInternal中的performClick方法
6、执行performClick中的OnClickListener的onClick方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值