TouchDelegate分析

在View.java中,使用TouchDelegate的代码很少,它的实现机制也非常的简单。先看看它在View.java中的代码:

    /**
     * The delegate to handle touch events that are physically in this view
     * but should be handled by another view.
     */
    private TouchDelegate mTouchDelegate = null;//说明了这个类对象的应用意义:把此View的触摸事件交由另外的View处理

    public boolean onTouchEvent(MotionEvent event) {
    ...
        if (mTouchDelegate != null) {
            if (mTouchDelegate.onTouchEvent(event)) {//如果设置了代理,那么事件交由代理处理,并且如果代理成功处理了事件,那么事件结束
                return true;
            }
        }

    public void setTouchDelegate(TouchDelegate delegate) {
        mTouchDelegate = delegate;
    }


    public TouchDelegate getTouchDelegate() {
        return mTouchDelegate;
    }

下面我们再来看看TouchDelegate.java源码:

/**
 * Helper class to handle situations where you want a view to have a larger touch area than its
 * actual view bounds. The view whose touch area is changed is called the delegate view. This
 * class should be used by an ancestor of the delegate. To use a TouchDelegate, first create an
 * instance that specifies the bounds that should be mapped to the delegate and the delegate
 * view itself.
 * <p>
 * The ancestor should then forward all of its touch events received in its
 * {@link android.view.View#onTouchEvent(MotionEvent)} to {@link #onTouchEvent(MotionEvent)}.
 * </p>
 */

//上面这段话注释在类的开头,它交代了TouchDelegate的使用意义——当我们希望View的触摸区域大于它实际的大小时可以使用这个代理实现和使用方法——它作为基类(即我们可以继承它写自己的代理),创建一个实例,这个实例需要指定一个区域和一个代理视图,代理视图可以是它本身。
//接下来看看它的构造函数,基本上就了解了如何使用这个辅助类。
    public TouchDelegate(Rect bounds, View delegateView) {
        mBounds = bounds;

        mSlop = ViewConfiguration.get(delegateView.getContext()).getScaledTouchSlop();
        mSlopBounds = new Rect(bounds);
        mSlopBounds.inset(-mSlop, -mSlop);
        mDelegateView = delegateView;
    }

//最重要的是onTouchEvent()这个函数,看看它是如何把触摸事件交给代理去处理的。首先说明一点,TouchDelegate是一个基类,我们可以继承它并按照自己的方式去实现代理
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int)event.getX();
        int y = (int)event.getY();
        boolean sendToDelegate = false;
        boolean hit = true;
        boolean handled = false;

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Rect bounds = mBounds;

            if (bounds.contains(x, y)) {//如果触摸点坐标在我们指定的代理的区域内,那么事件交给代理View处理
                mDelegateTargeted = true;
                sendToDelegate = true;
            }
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_MOVE:
            sendToDelegate = mDelegateTargeted;
            if (sendToDelegate) {
                Rect slopBounds = mSlopBounds;
                if (!slopBounds.contains(x, y)) {
                    hit = false;
                }
            }
            break;
        case MotionEvent.ACTION_CANCEL:
            sendToDelegate = mDelegateTargeted;
            mDelegateTargeted = false;
            break;
        }
        if (sendToDelegate) {
            final View delegateView = mDelegateView;
            
            if (hit) {
                // Offset event coordinates to be inside the target view
                event.setLocation(delegateView.getWidth() / 2, delegateView.getHeight() / 2);
            } else {
                // Offset event coordinates to be outside the target view (in case it does
                // something like tracking pressed state)
                int slop = mSlop;
                event.setLocation(-(slop * 2), -(slop * 2));
            }
            handled = delegateView.dispatchTouchEvent(event);//事件交由代理View去处理
        }
        return handled;
    }

通过上面这些源码可知,TouchDelegate有两种应用:

1.仅是拓宽(或缩小)触摸区域,把DelegateView设置为它本身,Bounds设置的区域就是代理点击的区域。这里有个疑惑,当点击区域在View本身的范围内时,ViewGroup才会把触摸事件分配给它。而在Bounds区域内,View获取不到触摸事件,又如何把触摸事件交给代理呢?

2.把触摸事件交给另外的View——DelegateView处理


你可能感兴趣的:(源码,android)