Android 滑动,拦截事件处理

之前一片文章 初略的讲了一些关于事件传递的基本内容,现在这片博客,
主要是具体去运用事件传递拦截的相关内容,

ok 具体要实现的目标就是, 
view 能够正常的吃掉点击事件, 但是如果是滑动事件时, 则是父View 来处理来滑动另一个View

基本原理就是 
在View group中得onInterceptTouchEvent 方法中判断是否是滑动,
如果是滑动,那么就返回true 自身去消费滑动事件,

还需要注意的是, 在处理滑动事件的时候需要注意 两个手指滑动的情况
即 另一个手指按下也能够继续滑动,

不多说了上代码: 

/**
 * 只处理 纵向滑动事件, 其他事件不做 处理
 */
public class CustomScrollViewGroup extends RelativeLayout {

    public static final String TAG = "CustomScrollViewGroup";

    public CustomScrollViewGroup(Context context) {
        super(context);
        init();
    }

    public CustomScrollViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CustomScrollViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private static final int MIN_DISTANCE_FOR_FLING = 25; // dips

    private OnScrollListener mOnScrollListener;

    private int mTouchSlop;
    protected VelocityTracker mVelocityTracker;
    private int mMinimumVelocity;
    private int mMaximumVelocity;

    /**
     * Position of the last motion event.
     */
    private float mLastMotionX;
    private float mLastMotionY;

    private float mInitialMotionY, mInitialMotionX;

    protected int mActivePointerId = INVALID_POINTER;
    private static final int INVALID_POINTER = -1;

    private boolean mIsUnableToDrag = false;

    private int mFlingDistance;

    private boolean mIsBeingDragged = false;
    boolean mScrollToEnd = false;//标记View是否已经完全消失,OvershootInterpolator回弹时间忽略
    private boolean mQuickReturn = false;

    boolean isTouchOnRecycleView = false;

    private void init() {

        final ViewConfiguration configuration = ViewConfiguration.get(getContext());
        mTouchSlop = configuration.getScaledTouchSlop();
        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();

        final float density = getContext().getResources().getDisplayMetrics().density;
        mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        LogUtil.d(TAG, "onInterceptTouchEvent ev = " + ev.getAction());
        final int action = ev.getAction();

        if (action == MotionEvent.ACTION_CANCEL
                || action == MotionEvent.ACTION_UP
                || (action != MotionEvent.ACTION_DOWN && mIsUnableToDrag)) {
            endDrag();
            return false;
        }

        switch (action & MotionEventCompat.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                // Remember where the motion event started
                int index = MotionEventCompat.getActionIndex(ev);
                mActivePointerId = MotionEventCompat.getPointerId(ev, index);
                if (mActivePointerId == INVALID_POINTER)
                    break;
                mLastMotionX = mInitialMotionX = MotionEventCompat.getX(ev, index);
                mInitialMotionY = mLastMotionY = MotionEventCompat.getY(ev, index);

                mIsBeingDragged = false;
                mIsUnableToDrag = false;
                break;

            case MotionEvent.ACTION_MOVE:
                final int activePointerIndex = getPointerIndex(ev, mActivePointerId);
                if (mActivePointerId == INVALID_POINTER) {
                    break;
                }
                final float currentY = MotionEventCompat.getY(ev, activePointerIndex);
                final float deltaY = mLastMotionY - currentY;
                determineDrag(ev);
                break;
        }

        if (!mIsBeingDragged) {
            if (mVelocityTracker == null) {
                mVelocityTracker = VelocityTracker.obtain();
            }
            mVelocityTracker.addMovement(ev);
        }
        return mIsBeingDragged || mQuickReturn;
    }

    private int getPointerIndex(MotionEvent ev, int id) {
        int activePointerIndex = MotionEventCompat.findPointerIndex(ev, id);
        if (activePointerIndex == -1)
            mActivePointerId = INVALID_POINTER;
        return activePointerIndex;
    }

    private int mScrollY = 0;

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        LogUtil.d(TAG, "onTouchEvent ev = " + ev.getAction());
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(ev);
        final int action = ev.getAction();

        switch (action & MotionEventCompat.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                // Remember where the motion event started
                int index = MotionEventCompat.getActionIndex(ev);
                mActivePointerId = MotionEventCompat.getPointerId(ev, index);
                mLastMotionY = mInitialMotionY = ev.getY();
                mLastMotionX = mInitialMotionX = ev.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                if (!mIsBeingDragged) {
                    determineDrag(ev);

                    if (mIsUnableToDrag)
                        return false;
                }

                if (mIsBeingDragged) {
                    final int activePointerIndex = getPointerIndex(ev, mActivePointerId);
                    if (mActivePointerId == INVALID_POINTER)
                        break;
                    final float y = MotionEventCompat.getY(ev, activePointerIndex);
                    final float deltaY = mLastMotionY - y;
                    mLastMotionY = y;
                    float oldScrollY = mScrollY;
                    float scrollY = oldScrollY + deltaY;
                    mLastMotionX += scrollY - (int) scrollY;
                    mScrollY = (int) scrollY;

                    if (mOnScrollListener != null) {
                        mOnScrollListener.onScroll(0, deltaY);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                if (mIsBeingDragged) {
                    final VelocityTracker velocityTracker = mVelocityTracker;
                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                    int initialVelocity = (int) VelocityTrackerCompat.getYVelocity(velocityTracker, mActivePointerId);
                    final int activePointerIndex = getPointerIndex(ev, mActivePointerId);
                    if (mActivePointerId != INVALID_POINTER) {
                        final float y = MotionEventCompat.getY(ev, activePointerIndex);
                        final int totalDelta = (int) (y - mInitialMotionY);// doww -> up detal
                        if (Math.abs(totalDelta) > mFlingDistance && Math.abs(initialVelocity) > mMinimumVelocity) {
                            if (initialVelocity > 0 && totalDelta > 0) {
                                // 向下滑
                                if (mOnScrollListener != null) {
                                    mOnScrollListener.onFling(false);
                                }
                            } else if (initialVelocity < 0 && totalDelta < 0) {
                                // 向上滑
                                if (mOnScrollListener != null) {
                                    mOnScrollListener.onFling(true);
                                }
                            } else {
                                if (mOnScrollListener != null) {
                                    mOnScrollListener.onScrollOver();
                                }
                            }
                        } else {
                            if (mOnScrollListener != null) {
                                mOnScrollListener.onScrollOver();
                            }
                            // 不是 fling 最后是 划上 还是划下  外面判断
                        }

                    }
                    mActivePointerId = INVALID_POINTER;
                    endDrag();
                }
                break;
            case MotionEventCompat.ACTION_POINTER_DOWN: {
                final int indexx = MotionEventCompat.getActionIndex(ev);
                mLastMotionY = MotionEventCompat.getY(ev, indexx);
                mLastMotionX = MotionEventCompat.getX(ev, indexx);
                mActivePointerId = MotionEventCompat.getPointerId(ev, indexx);
                break;
            }
            case MotionEventCompat.ACTION_POINTER_UP:
                int pointerIndex = getPointerIndex(ev, mActivePointerId);
                if (mActivePointerId == INVALID_POINTER)
                    break;
                mLastMotionY = MotionEventCompat.getY(ev, pointerIndex);
                mLastMotionX = MotionEventCompat.getX(ev, pointerIndex);
                break;
        }

        return true;
    }

    private void determineDrag(MotionEvent ev) {
        final int activePointerId = mActivePointerId;
        final int pointerIndex = getPointerIndex(ev, activePointerId);
        if (activePointerId == INVALID_POINTER || pointerIndex == INVALID_POINTER)
            return;
        final float x = MotionEventCompat.getX(ev, pointerIndex);
        final float dx = x - mLastMotionX;
        final float xDiff = Math.abs(dx);
        final float y = MotionEventCompat.getY(ev, pointerIndex);
        final float dy = y - mLastMotionY;
        final float yDiff = Math.abs(dy);
        if (yDiff > mTouchSlop && yDiff > xDiff) {
            startDrag();
            mLastMotionX = x;
            mLastMotionY = y;
        } else if (xDiff > mTouchSlop) {
            mIsUnableToDrag = true;
        }
    }

    // 开始滑动
    private void startDrag() {
        mIsBeingDragged = true;
        mQuickReturn = false;
        mScrollToEnd = false;
    }

    private void endDrag() {
        mQuickReturn = false;
        mIsBeingDragged = false;
        mIsUnableToDrag = false;
        mActivePointerId = INVALID_POINTER;

        if (mVelocityTracker != null) {
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }

    public void setOnScrollListener(OnScrollListener onScrollListener) {
        mOnScrollListener = onScrollListener;
    }

    public interface OnScrollListener {
        void onScroll(float distanceX, float distanceY);

        void onFling(boolean isFlingUp);

        void onScrollOver();

    }
}

上面的是最主要的ViewGroup 
下面在来看看 activity 中得代码 

public class MainActivity extends AppCompatActivity {
    public static final String TAG = "MainActivity";

    Button mButton;
    View mView;
    CustomScrollViewGroup mCustomScrollViewGroup;

    int maxTranY;

    float currentTransY = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton = (Button) findViewById(R.id.btn);
        mView = findViewById(R.id.scrolledView);
        mCustomScrollViewGroup = (CustomScrollViewGroup) findViewById(R.id.customscrollviewgroup);

        maxTranY = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 300, getResources().getDisplayMetrics());

        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "click btn", Toast.LENGTH_SHORT).show();
            }
        });

        mCustomScrollViewGroup.setOnScrollListener(new CustomScrollViewGroup.OnScrollListener() {
            /**
             * 滑动 的箭头
             * @param distanceX 向左滑动 为正
             * @param distanceY 向上滑动 为正
             */
            @Override
            public void onScroll(float distanceX, float distanceY) {
                if (isAnimating) {
                    return;
                }
                currentTransY = currentTransY - distanceY;
                if (currentTransY < -maxTranY) {
                    currentTransY = -maxTranY;
                }

                if (currentTransY > 0) {
                    currentTransY = 0;
                }
                mView.setTranslationY(currentTransY);
                LogUtil.d(TAG, "onScroll distanceX = " + distanceX + " , distanceY = " + distanceY + ", currentTransY = " + currentTransY);
            }

            /**
             * 快速滑动的回调
             * @param isFlingUp 是否是向上快速滑动
             */
            @Override
            public void onFling(boolean isFlingUp) {
                if (isAnimating) {
                    return;
                }
                LogUtil.d(TAG, "onFling isFlingUp = " + isFlingUp);
                if (isFlingUp) {
                    animatorScrollUp();
                } else {
                    animatorScrollDowm();
                }
            }

            /**
             * 滑动结束的监听
             */
            @Override
            public void onScrollOver() {
                if (isAnimating) {
                    return;
                }
                LogUtil.d(TAG, "onScrollOver");
                if (currentTransY < -maxTranY / 2) {// 向上滑超过了 1/2
                    animatorScrollUp();
                } else {
                    animatorScrollDowm();
                }
            }
        });

    }

    boolean isAnimating = false;

    private void animatorScrollUp() {
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mView, "TranslationY", mView.getTranslationY(), -maxTranY);
        objectAnimator.setDuration(300);
        isAnimating = true;
        objectAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                currentTransY = -maxTranY;
                isAnimating = false;
            }
        });
        objectAnimator.start();
    }

    private void animatorScrollDowm() {
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mView, "TranslationY", mView.getTranslationY(), 0);
        objectAnimator.setDuration(300);
        isAnimating = true;
        objectAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                currentTransY = 0;
                isAnimating = false;
            }
        });
        objectAnimator.start();
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值