Android事件分发 (一)

本文通过实例演示了Android中事件分发的过程,并解释了点击事件与触摸事件的关系及执行顺序。详细探讨了如何通过返回值控制事件的传递,以及不同组件如Button与ImageView在事件处理上的差异。

Android事件分发 (一)

前言:最近项目中用到了许多事件分发的知识,我也是似懂非懂的样子,但是掌握好事件分发真的很重要,我结合大牛的blog跟自己的理解,决定写一篇博客来记录下自己所学的东西,废话不说了,上代码!!
首先写了一个很简单的布局,里面就放了一个button,给button添加了一个点击事件跟一个触摸事件监听。

mButton=(Button) findViewById(R.id.id_bt);
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i(TAG, "onclick----->");
            }
        });
        mButton.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action=event.getAction();
                switch (action) {
                case MotionEvent.ACTION_DOWN:
                    Log.i(TAG, "ACTION_DOWN----->"+action);
                    break;
                case MotionEvent.ACTION_MOVE:
                    Log.i(TAG, "ACTION_MOVE----->"+action);
                    break;
                case MotionEvent.ACTION_UP:
                    Log.i(TAG, "ACTION_UP----->"+action);
                    break;
                default:
                    break;
                }
                return false;
            }
        });
    }

运行代码后打印的日志为:

06-28 11:13:56.288: I/MainActivity(3355): ACTION_DOWN----->0
06-28 11:13:56.368: I/MainActivity(3355): ACTION_UP----->1
06-28 11:13:56.404: I/MainActivity(3355): onclick----->

也就是说先执行了ontouch方法然后再执行的onclick方法,这是为什么呢?我们看看源码, 首先不管执行的是哪个方法,最先执行的是在View类中的dispatchTouchEvent(MotionEvent event)方法,我们看看它长什么样

  */
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(event, 0);
        }

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

            if (onTouchEvent(event)) {
                return true;
            }
        }

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifi

er.onUnhandledEvent(event, 0);
        }
        return false;
    }

捡重点的看,当mOnTouchListener!=null并且控件是enable并且当onTouch返回true的时候,dispatchTouchEvent方法就会返回true,否则就会去执行onTouchEvent方法,

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

            if (onTouchEvent(event)) {
                return true;
            }
        }

我们现在的代码是在ontouch方法里面返回的false,我们返回一个true试试,

mButton.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action=event.getAction();
                switch (action) {
                case MotionEvent.ACTION_DOWN:
                    Log.i(TAG, "ACTION_DOWN----->"+action);
                    break;
                case MotionEvent.ACTION_MOVE:
                    Log.i(TAG, "ACTION_MOVE----->"+action);
                    break;
                case MotionEvent.ACTION_UP:
                    Log.i(TAG, "ACTION_UP----->"+action);
                    break;
                default:
                    break;
                }
                return true;
            }
        });

结果为:onclick方法不再执行了,我们的点击事件没啦。由此可得知,我们的点击事件是在ontouchevent方法里面执行的,这也说明了前面的结果,ontouch事件优先于ontouchevent事件执行。

06-28 11:24:59.708: I/MainActivity(3532): ACTION_DOWN----->0
06-28 11:24:59.792: I/MainActivity(3532): ACTION_UP----->1

我们得出结论,只有当dispatchTouchEvent方法返回true的时候event的下一个动作才会执行,我们测试一下:我们在ontouch的action_down中返回false,看看action_up还会不会执行

mButton.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action=event.getAction();
                switch (action) {
                case MotionEvent.ACTION_DOWN:
                    Log.i(TAG, "ACTION_DOWN----->"+action);
                    return false;
                case MotionEvent.ACTION_MOVE:
                    Log.i(TAG, "ACTION_MOVE----->"+action);
                    break;
                case MotionEvent.ACTION_UP:
                    Log.i(TAG, "ACTION_UP----->"+action);
                    break;
                default:
                    break;
                }
                return false;
            }
        });

结果:

06-28 11:30:52.724: I/MainActivity(3664): ACTION_DOWN----->0
06-28 11:30:52.796: I/MainActivity(3664): ACTION_UP----->1
06-28 11:30:52.820: I/MainActivity(3664): onclick----->

我靠man,这不是误导别人嘛,我刚开始的时候也懵里懵懂的,后面看了源码,还真是这样咯。因为我们这里用的是Button做的测试,我们这回换成ImageView试试,只执行了ACTION_DOWN,那Button为何又可以向下执行呢?带着疑问又看看源码,
结果为:

06-28 11:30:52.724: I/MainActivity(3664): ACTION_DOWN----->0

onTouchEvent源码:不管你干了什么,只要是CLICKABLE 或者是LONG_CLICKABLE的组件,我就直接返回true,也就验证了为什么Button在outouch里面返回了false,事件还是向下传递,因为在onTouchEvent方法里面返回了true,从而dipatchTouchEvent方法返回了true。(如果我们也要像Button一样,不管ontouch返回的是true还是false,事件动作照样传递的话,只需要加上CLICKABLE =true或者LONG_CLICKABLE=true的操作即可)

   if (((viewFlags & CLICKABLE) == CLICKABLE ||
                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
                .....
                return true;
   }

View的事件分发就到此结束了,刚才开始写博客,老手可以略过,^_^!!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值