SwipeRefreshLayout和bannerView轮播冲突解决

SwipeRefreshLayout和ConvenientBanner广告轮播事件冲突解决

 

查看布局,分析一下布局,这个布局是很常规的首页布局,一个SwipeRefreshLayout下拉刷新包裹一个带headlistview。其中head头部有个广告轮播的控件,可以左右滑动,下拉刷新是上下滑动。

如果直接使用,你会发现,你左右滑动的时候,很不灵敏,有时候会触动下拉刷新。

 

可以发现淘宝那些广告条,左右滑动非常顺畅,上下滑动下拉刷新也不影响广告轮播。这就是这个博客要解决的一个问题,解决广告条左右滑动和下拉刷新的冲突。

 

我们理想的处理就是,我们只想直接下拉(x方向没有发生很大的变化)就是下拉刷新,其他小动作大动作的左右滑动,都属于广告轮播。


 


这样我们先确定处理事件处理分成2个情况。

A,笔直滑动,x坐标左右变化不大。(下拉刷新)

B,左右滑动,斜滑动(广告条)

 

目标确定了,明确了分2中情况。我们就先从下拉刷新源码入手,因为这样思路比较明确,比较事件传递,先从父类传到子类。那个过程就不再详说了,不明白的可以看一下其他优秀的博客,这篇不错:http://blog.csdn.net/hyp712/article/details/8777835

 

 

查看SwipeRefreshLayout源码,其中onInterceptTouchEvent拦截就是重点


  1. @Override  
  2. public boolean onInterceptTouchEvent(MotionEvent ev) {  
  3.     ensureTarget();  
  4.   
  5.     final int action = MotionEventCompat.getActionMasked(ev);  
  6.   
  7.     if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {  
  8.         mReturningToStart = false;  
  9.     }  
  10.   
  11.     if (!isEnabled() || mReturningToStart || canChildScrollUp()  
  12.             || mRefreshing || mNestedScrollInProgress) {  
  13.         // Fail fast if we’re not in a state where a swipe is possible  
  14.         return false;  
  15.     }  
  16.   
  17.     switch (action) {  
  18.         case MotionEvent.ACTION_DOWN:  
  19.             setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCircleView.getTop(), true);  
  20.             mActivePointerId = MotionEventCompat.getPointerId(ev, 0);  
  21.             mIsBeingDragged = false;  
  22.             final float initialDownY = getMotionEventY(ev, mActivePointerId);  
  23.             if (initialDownY == -1) {  
  24.                 return false;  
  25.             }  
  26.             mInitialDownY = initialDownY;  
  27.             break;  
  28.   
  29.         case MotionEvent.ACTION_MOVE:  
  30.             if (mActivePointerId == INVALID_POINTER) {  
  31.                 Log.e(LOG_TAG, ”Got ACTION_MOVE event but don’t have an active pointer id.”);  
  32.                 return false;  
  33.             }  
  34.   
  35.             final float y = getMotionEventY(ev, mActivePointerId);  
  36.             if (y == -1) {  
  37.                 return false;  
  38.             }  
  39.             final float yDiff = y - mInitialDownY;  
  40.             if (yDiff > mTouchSlop && !mIsBeingDragged) {  
  41.                 mInitialMotionY = mInitialDownY + mTouchSlop;  
  42.                 mIsBeingDragged = true;  
  43.                 mProgress.setAlpha(STARTING_PROGRESS_ALPHA);  
  44.             }  
  45.             break;  
  46.   
  47.         case MotionEventCompat.ACTION_POINTER_UP:  
  48.             onSecondaryPointerUp(ev);  
  49.             break;  
  50.   
  51.         case MotionEvent.ACTION_UP:  
  52.         case MotionEvent.ACTION_CANCEL:  
  53.             mIsBeingDragged = false;  
  54.             mActivePointerId = INVALID_POINTER;  
  55.             break;  
  56.     }  
  57.   
  58.     return mIsBeingDragged;  
  59. }  
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    ensureTarget();

    final int action = MotionEventCompat.getActionMasked(ev);

    if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {
        mReturningToStart = false;
    }

    if (!isEnabled() || mReturningToStart || canChildScrollUp()
            || mRefreshing || mNestedScrollInProgress) {
        // Fail fast if we're not in a state where a swipe is possible
        return false;
    }

    switch (action) {
        case MotionEvent.ACTION_DOWN:
            setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCircleView.getTop(), true);
            mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
            mIsBeingDragged = false;
            final float initialDownY = getMotionEventY(ev, mActivePointerId);
            if (initialDownY == -1) {
                return false;
            }
            mInitialDownY = initialDownY;
            break;

        case MotionEvent.ACTION_MOVE:
            if (mActivePointerId == INVALID_POINTER) {
                Log.e(LOG_TAG, "Got ACTION_MOVE event but don't have an active pointer id.");
                return false;
            }

            final float y = getMotionEventY(ev, mActivePointerId);
            if (y == -1) {
                return false;
            }
            final float yDiff = y - mInitialDownY;
            if (yDiff > mTouchSlop && !mIsBeingDragged) {
                mInitialMotionY = mInitialDownY + mTouchSlop;
                mIsBeingDragged = true;
                mProgress.setAlpha(STARTING_PROGRESS_ALPHA);
            }
            break;

        case MotionEventCompat.ACTION_POINTER_UP:
            onSecondaryPointerUp(ev);
            break;

        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            mIsBeingDragged = false;
            mActivePointerId = INVALID_POINTER;
            break;
    }

    return mIsBeingDragged;
}

上面的一系列逻辑,最后mIsBeingDragged就是返回觉得是否拦截事件,我们就在这个方法入手,我们先判断,如果x坐标变化大于y坐标的变化,那么我们就认为这个是左右滑动的,下拉刷新不处理。(也可以做其他判断,这里测试过x>y效果还不错)

 

我们新建一个自定义view RefreshLayout 继承SwipeRefreshLayout,重新它的onInterceptTouchEvent方法。

(就是下面这几行代码,返回false然后下拉刷新控件不执行onTouchEvent事件)

  1. float lastx = 0;  
  2. float lasty = 0;  
  3. boolean ismovepic = false;  
  4. @Override  
  5. public boolean onInterceptTouchEvent(MotionEvent ev) {  
  6.   
  7.   
  8.   
  9.     if (ev.getAction() ==MotionEvent.ACTION_DOWN){  
  10.         lastx = ev.getX();  
  11.         lasty = ev.getY();  
  12.         ismovepic = false;  
  13.         return super.onInterceptTouchEvent(ev);  
  14.     }  
  15.   
  16.     final int action = MotionEventCompat.getActionMasked(ev);  
  17.     VLog.v(ev.getX() + ”—” + ev.getY());  
  18.   
  19.     int x2 = (int) Math.abs(ev.getX() - lastx);  
  20.     int y2 = (int) Math.abs(ev.getY() - lasty);  
  21.   
  22.     //滑动图片最小距离检查  
  23.     VLog.v(”滑动差距 - >” + x2 + “–” + y2);  
  24.     if (x2>y2){  
  25.         if (x2>=100)ismovepic = true;  
  26.         return false;  
  27.     }  
  28.   
  29.     //是否移动图片(下拉刷新不处理)  
  30.     if (ismovepic){  
  31.         VLog.v(”滑动差距 - >” + x2 + “–” + y2);  
  32.         return false;  
  33.     }  
  34.   
  35.     boolean isok = super.onInterceptTouchEvent(ev);  
  36.   
  37.     VLog.v(”isok ->” + isok);  
  38.   
  39.     return isok;  
  40. }  
float lastx = 0;
float lasty = 0;
boolean ismovepic = false;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {



    if (ev.getAction() ==MotionEvent.ACTION_DOWN){
        lastx = ev.getX();
        lasty = ev.getY();
        ismovepic = false;
        return super.onInterceptTouchEvent(ev);
    }

    final int action = MotionEventCompat.getActionMasked(ev);
    VLog.v(ev.getX() + "---" + ev.getY());

    int x2 = (int) Math.abs(ev.getX() - lastx);
    int y2 = (int) Math.abs(ev.getY() - lasty);

    //滑动图片最小距离检查
    VLog.v("滑动差距 - >" + x2 + "--" + y2);
    if (x2>y2){
        if (x2>=100)ismovepic = true;
        return false;
    }

    //是否移动图片(下拉刷新不处理)
    if (ismovepic){
        VLog.v("滑动差距 - >" + x2 + "--" + y2);
        return false;
    }

    boolean isok = super.onInterceptTouchEvent(ev);

    VLog.v("isok ->" + isok);

    return isok;
}


上面判断,为了效果更好,加入了ismovepic 判断,这个判断也很简单,就是如果我按住图片,然后左右滑动一点点,然后一直下拉,超出了广告条的位置,这样的话,广告条处理不了超出位置的点击事件,就有个bug,下拉刷新会再次出现。所以如果设置它左右滑动后,y坐标变化就算超过100(100可以自由设置,我这里先定100,测试效果还不错),也就是脱离广告条位置,我们也不能让下拉刷新出现。

 

加入这个判断后,手势划来划去都非常灵敏。


ps:按照这个思路,其实其他的下拉刷新控件,大致的事件冲突解决方案思路也差不多,有更好的方法可以留言讨论一下。


SwipeRefreshLayout和ConvenientBanner广告轮播事件冲突解决

 

查看布局,分析一下布局,这个布局是很常规的首页布局,一个SwipeRefreshLayout下拉刷新包裹一个带headlistview。其中head头部有个广告轮播的控件,可以左右滑动,下拉刷新是上下滑动。

如果直接使用,你会发现,你左右滑动的时候,很不灵敏,有时候会触动下拉刷新。

 

可以发现淘宝那些广告条,左右滑动非常顺畅,上下滑动下拉刷新也不影响广告轮播。这就是这个博客要解决的一个问题,解决广告条左右滑动和下拉刷新的冲突。

 

我们理想的处理就是,我们只想直接下拉(x方向没有发生很大的变化)就是下拉刷新,其他小动作大动作的左右滑动,都属于广告轮播。


 


这样我们先确定处理事件处理分成2个情况。

A,笔直滑动,x坐标左右变化不大。(下拉刷新)

B,左右滑动,斜滑动(广告条)

 

目标确定了,明确了分2中情况。我们就先从下拉刷新源码入手,因为这样思路比较明确,比较事件传递,先从父类传到子类。那个过程就不再详说了,不明白的可以看一下其他优秀的博客,这篇不错:http://blog.csdn.net/hyp712/article/details/8777835

 

 

查看SwipeRefreshLayout源码,其中onInterceptTouchEvent拦截就是重点


  1. @Override  
  2. public boolean onInterceptTouchEvent(MotionEvent ev) {  
  3.     ensureTarget();  
  4.   
  5.     final int action = MotionEventCompat.getActionMasked(ev);  
  6.   
  7.     if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {  
  8.         mReturningToStart = false;  
  9.     }  
  10.   
  11.     if (!isEnabled() || mReturningToStart || canChildScrollUp()  
  12.             || mRefreshing || mNestedScrollInProgress) {  
  13.         // Fail fast if we’re not in a state where a swipe is possible  
  14.         return false;  
  15.     }  
  16.   
  17.     switch (action) {  
  18.         case MotionEvent.ACTION_DOWN:  
  19.             setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCircleView.getTop(), true);  
  20.             mActivePointerId = MotionEventCompat.getPointerId(ev, 0);  
  21.             mIsBeingDragged = false;  
  22.             final float initialDownY = getMotionEventY(ev, mActivePointerId);  
  23.             if (initialDownY == -1) {  
  24.                 return false;  
  25.             }  
  26.             mInitialDownY = initialDownY;  
  27.             break;  
  28.   
  29.         case MotionEvent.ACTION_MOVE:  
  30.             if (mActivePointerId == INVALID_POINTER) {  
  31.                 Log.e(LOG_TAG, ”Got ACTION_MOVE event but don’t have an active pointer id.”);  
  32.                 return false;  
  33.             }  
  34.   
  35.             final float y = getMotionEventY(ev, mActivePointerId);  
  36.             if (y == -1) {  
  37.                 return false;  
  38.             }  
  39.             final float yDiff = y - mInitialDownY;  
  40.             if (yDiff > mTouchSlop && !mIsBeingDragged) {  
  41.                 mInitialMotionY = mInitialDownY + mTouchSlop;  
  42.                 mIsBeingDragged = true;  
  43.                 mProgress.setAlpha(STARTING_PROGRESS_ALPHA);  
  44.             }  
  45.             break;  
  46.   
  47.         case MotionEventCompat.ACTION_POINTER_UP:  
  48.             onSecondaryPointerUp(ev);  
  49.             break;  
  50.   
  51.         case MotionEvent.ACTION_UP:  
  52.         case MotionEvent.ACTION_CANCEL:  
  53.             mIsBeingDragged = false;  
  54.             mActivePointerId = INVALID_POINTER;  
  55.             break;  
  56.     }  
  57.   
  58.     return mIsBeingDragged;  
  59. }  
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    ensureTarget();

    final int action = MotionEventCompat.getActionMasked(ev);

    if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {
        mReturningToStart = false;
    }

    if (!isEnabled() || mReturningToStart || canChildScrollUp()
            || mRefreshing || mNestedScrollInProgress) {
        // Fail fast if we're not in a state where a swipe is possible
        return false;
    }

    switch (action) {
        case MotionEvent.ACTION_DOWN:
            setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCircleView.getTop(), true);
            mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
            mIsBeingDragged = false;
            final float initialDownY = getMotionEventY(ev, mActivePointerId);
            if (initialDownY == -1) {
                return false;
            }
            mInitialDownY = initialDownY;
            break;

        case MotionEvent.ACTION_MOVE:
            if (mActivePointerId == INVALID_POINTER) {
                Log.e(LOG_TAG, "Got ACTION_MOVE event but don't have an active pointer id.");
                return false;
            }

            final float y = getMotionEventY(ev, mActivePointerId);
            if (y == -1) {
                return false;
            }
            final float yDiff = y - mInitialDownY;
            if (yDiff > mTouchSlop && !mIsBeingDragged) {
                mInitialMotionY = mInitialDownY + mTouchSlop;
                mIsBeingDragged = true;
                mProgress.setAlpha(STARTING_PROGRESS_ALPHA);
            }
            break;

        case MotionEventCompat.ACTION_POINTER_UP:
            onSecondaryPointerUp(ev);
            break;

        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            mIsBeingDragged = false;
            mActivePointerId = INVALID_POINTER;
            break;
    }

    return mIsBeingDragged;
}

上面的一系列逻辑,最后mIsBeingDragged就是返回觉得是否拦截事件,我们就在这个方法入手,我们先判断,如果x坐标变化大于y坐标的变化,那么我们就认为这个是左右滑动的,下拉刷新不处理。(也可以做其他判断,这里测试过x>y效果还不错)

 

我们新建一个自定义view RefreshLayout 继承SwipeRefreshLayout,重新它的onInterceptTouchEvent方法。

(就是下面这几行代码,返回false然后下拉刷新控件不执行onTouchEvent事件)

  1. float lastx = 0;  
  2. float lasty = 0;  
  3. boolean ismovepic = false;  
  4. @Override  
  5. public boolean onInterceptTouchEvent(MotionEvent ev) {  
  6.   
  7.   
  8.   
  9.     if (ev.getAction() ==MotionEvent.ACTION_DOWN){  
  10.         lastx = ev.getX();  
  11.         lasty = ev.getY();  
  12.         ismovepic = false;  
  13.         return super.onInterceptTouchEvent(ev);  
  14.     }  
  15.   
  16.     final int action = MotionEventCompat.getActionMasked(ev);  
  17.     VLog.v(ev.getX() + ”—” + ev.getY());  
  18.   
  19.     int x2 = (int) Math.abs(ev.getX() - lastx);  
  20.     int y2 = (int) Math.abs(ev.getY() - lasty);  
  21.   
  22.     //滑动图片最小距离检查  
  23.     VLog.v(”滑动差距 - >” + x2 + “–” + y2);  
  24.     if (x2>y2){  
  25.         if (x2>=100)ismovepic = true;  
  26.         return false;  
  27.     }  
  28.   
  29.     //是否移动图片(下拉刷新不处理)  
  30.     if (ismovepic){  
  31.         VLog.v(”滑动差距 - >” + x2 + “–” + y2);  
  32.         return false;  
  33.     }  
  34.   
  35.     boolean isok = super.onInterceptTouchEvent(ev);  
  36.   
  37.     VLog.v(”isok ->” + isok);  
  38.   
  39.     return isok;  
  40. }  
float lastx = 0;
float lasty = 0;
boolean ismovepic = false;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {



    if (ev.getAction() ==MotionEvent.ACTION_DOWN){
        lastx = ev.getX();
        lasty = ev.getY();
        ismovepic = false;
        return super.onInterceptTouchEvent(ev);
    }

    final int action = MotionEventCompat.getActionMasked(ev);
    VLog.v(ev.getX() + "---" + ev.getY());

    int x2 = (int) Math.abs(ev.getX() - lastx);
    int y2 = (int) Math.abs(ev.getY() - lasty);

    //滑动图片最小距离检查
    VLog.v("滑动差距 - >" + x2 + "--" + y2);
    if (x2>y2){
        if (x2>=100)ismovepic = true;
        return false;
    }

    //是否移动图片(下拉刷新不处理)
    if (ismovepic){
        VLog.v("滑动差距 - >" + x2 + "--" + y2);
        return false;
    }

    boolean isok = super.onInterceptTouchEvent(ev);

    VLog.v("isok ->" + isok);

    return isok;
}


上面判断,为了效果更好,加入了ismovepic 判断,这个判断也很简单,就是如果我按住图片,然后左右滑动一点点,然后一直下拉,超出了广告条的位置,这样的话,广告条处理不了超出位置的点击事件,就有个bug,下拉刷新会再次出现。所以如果设置它左右滑动后,y坐标变化就算超过100(100可以自由设置,我这里先定100,测试效果还不错),也就是脱离广告条位置,我们也不能让下拉刷新出现。

 

加入这个判断后,手势划来划去都非常灵敏。


ps:按照这个思路,其实其他的下拉刷新控件,大致的事件冲突解决方案思路也差不多,有更好的方法可以留言讨论一下。


猜你喜欢

转载自blog.csdn.net/android_zhengyongbo/article/details/80077288
今日推荐