关于ViewGroup的触摸事件拦截

本文详细解释了onInterceptTouchEvent()和onTouchEvent()方法的区别,前者用于决定是否拦截触摸事件,若返回true则事件由父ViewGroup处理;后者用于实际处理触摸事件。通过示例代码展示了如何在自定义ViewGroup中实现这两个方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

onInterceptTouchEvent() 方法和 onTouchEvent() 的区别:

有梯子的直接看这里

The onInterceptTouchEvent() method is called whenever a touch event is detected on the surface of a ViewGroup, including on the surface of its children. If onInterceptTouchEvent() returns true, the MotionEvent is intercepted, meaning it will be not be passed on to the child, but rather to the onTouchEvent() method of the parent.

翻译成大白话就是:
onInterceptTouchEvent() 方法如果你的返回值是true,那么这个触摸事件我们就把它拦截了,他里面的子view就没办法获取到这个事件了(不管你摸的是不是他的子view,只要你摸的地方在这个viewgroup范围内)。

然后这个事件就传到viewgroup的onTouchEvent()方法里了,在这里你可以根据滑动的距离想干嘛干嘛,你viewgroup里的子view永远都得不到这个事件了。

来段代码理解下:

在下面的代码里,我们写一个MyViewGroup继承自ViewGroup。MyViewGroup里面可能会包含几个子view。如果你干净的小手在在上面水平滑动,我们就不让子view得到这个触摸事件,让MyViewGroup来处理这个事件(也就是看上去里面的内容滑动了一下)。如果你按下了子view里的button,或者竖直的滑动了里面的子view,那么我们的viewgroup就不应该拦截这个事件了,因为我们的目的是按里面的按钮。在这种情况下,onInterceptTouchEvent()就应该返回false了,而且viewgroup的onTouchEvent()方法也不会被调用。

public class MyViewGroup extends ViewGroup {

    private int mTouchSlop;
    private float mDownX; 
    //手指刚落下的坐标,用来计算滑动距离的
    ...

    ViewConfiguration vc = ViewConfiguration.get(view.getContext());
    mTouchSlop = vc.getScaledTouchSlop();
    //获得最小有效滑动距离(系统自带的方法)
    ...

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        /*
         * 这个方法决定了我们是不是要拦截这个触摸事件
         * 如果返回true,onTouchEvent()就会被调用
         */


        final int action = MotionEventCompat.getActionMasked(ev);


        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
            // 如果这个触摸被取消了,或者手指抬起来了
            mIsScrolling = false;
            return false; // 返回false,不拦截事件,交给子view
        }

        switch (action) {
            case MotionEvent.ACTION_MOVE: {
                if (mIsScrolling) {
                    // 我们正在滑动呢,所以赶紧拦截下来吧
                    return true;
                }

                // 这个计算方法谷歌很不厚道的留给了读者自行解决。。。译者改天自己补上吧。。
                final int xDiff = calculateDistanceX(ev);

                //如果滑动距离大于最小有效距离,那么就拦截下来
                if (xDiff > mTouchSlop) {

                    mIsScrolling = true;
                    return true;
                }
                break;

            case MotionEvent.ACTION_DOWN:
                //手指落下时的坐标,用来计算滑动距离的
                mDownX = ev.getRawX();
            return false;
            }
            ...
        }

        //其他情况下我们就不拦截触摸事件了,交给子view处理这个触摸事件
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        // 在这我们真正的开始处理滑动事件 
        //(例如 if ( ev.getAction() == ACTION_MOVE)
        //{想干嘛干嘛}
        //注意这个方法只有在 onInterceptTouchEvent返回true的时候才被调用(敲黑板!)
        ...
    }


//补上补上
private int calculateDistanceX(MotionEvent ev) {
        return (int) (ev.getRawX() - mDownX);
    }

}

原创翻译,转载请注明http://blog.youkuaiyun.com/sinat_31598337
联系我:Joeys苏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值