基於原生SwipeRefreshLayout修改爲橫向刷新組件

網上有很多橫向滑動的組件但是都是自己去實現的。於是我就想能不能偷個懶直接用原生的改一下哈哈。結果還真行。只不過可能不支持ListView。ViewGroup(RecyclerView)都是可以的,要是想支持ListView自己去實現下他們提供的OnChildScrollUpCallback中的canChildScrollLeft方法判斷是否能從左邊往右邊滑動,top被我改成了Left因爲是橫向滑動嘛。
先上代碼
https://github.com/Darksiderlyd/HSwipeRefreshLayout

第一步:
首先看下拉組件的佈局添加之前添加在頂部現在改一下添加到左邊,以下是修改後的代碼:

@Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        final int width = getMeasuredWidth();
        final int height = getMeasuredHeight();
        if (getChildCount() == 0) {
            return;
        }
        if (mTarget == null) {
            ensureTarget();
        }
        if (mTarget == null) {
            return;
        }
        final View child = mTarget;
        final int childLeft = getPaddingLeft();
        final int childTop = getPaddingTop();
        final int childWidth = width - getPaddingLeft() - getPaddingRight();
        final int childHeight = height - getPaddingTop() - getPaddingBottom();
        child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
        int circleWidth = mCircleView.getMeasuredWidth();
        int circleHeight = mCircleView.getMeasuredHeight();
        mCircleView.layout(mCurrentTargetOffsetLeft, (height / 2 - circleHeight / 2),
                mCurrentTargetOffsetLeft + circleWidth, (height / 2 + circleHeight / 2));
    }

第二步:
修改各種與Y、Top、Vertical有關的參數

 private float mInitialMotionX;
 private float mInitialDownX;

1.這兩個參數之前是Y改成X因爲是橫向滑動和X軸有關和Y軸無關。
然後修改這兩個參數相關的位置的getY改成X的。
這些方法主要在以下幾個方法中:

onInterceptTouchEvent()
onTouchEvent()

//此方法中的dy改爲dx以下爲修改後方法
@Override
public void onNestedScroll(final View target, final int dxConsumed, final int dyConsumed,
                           final int dxUnconsumed, final int dyUnconsumed) {
    // Dispatch up to the nested parent first
    dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
            mParentOffsetInWindow);

    // This is a bit of a hack. Nested scrolling works from the bottom up, and as we are
    // sometimes between two nested scrolling views, we need a way to be able to know when any
    // nested scrolling parent has stopped handling events. We do that by using the
    // 'offset in window 'functionality to see if we have been moved from the event.
    // This is a decent indication of whether we should take over theeventstream or not.
    final int dx = dxUnconsumed + mParentOffsetInWindow[0];
   if (dx < 0 && !canChildScrollUp()) {
        mTotalUnconsumed += Math.abs(dx);
        moveSpinner(mTotalUnconsumed);
    }
}
 
 
 @Override
 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
    // If we are in the middle of consuming, a scroll, then we want to move the spinner back up
    // before allowing the list to scroll
    if (dx > 0 && mTotalUnconsumed > 0) {
        if (dx > mTotalUnconsumed) {
            consumed[0] = dx - (int) mTotalUnconsumed;
            mTotalUnconsumed = 0;
           } else {
               mTotalUnconsumed -= dx;
               consumed[0] = dx;
           }
           moveSpinner(mTotalUnconsumed);
    }

    // If a client layout is using a custom start position for the circle
    // view, they mean to hide it again before scrolling the child view
    // If we get back to mTotalUnconsumed == 0 and there is more to go, hide
    // the circle so it isn't exposed if its blocking content is moved
     if (mUsingCustomStart && dx > 0 && mTotalUnconsumed == 0
             && Math.abs(dx - consumed[0]) > 0) {
         mCircleView.setVisibility(View.GONE);
    }

     // Now let our nested parent consume the leftovers
     final int[] parentConsumed = mParentScrollConsumed;
     if (dispatchNestedPreScroll(dx - consumed[0], dy - consumed[1], parentConsumed, null)) {
         consumed[0] += parentConsumed[0];
         consumed[1] += parentConsumed[1];
    }
}

2.把View.getTop() 都改爲View.getLeft():

mCircleView.getLeft()

3.修改和Vertical相關的參數,修改canScrollVertically(參數小於0爲從上往下滑動,大於零從下往上)爲canScrollHorizontally(參數小於0爲從左往右滑動,大於零從右往左),SCROLL_AXIS_VERTICAL修改爲SCROLL_AXIS_HORIZONTAL,以下代碼中去掉了ListView的判斷看源碼他只判斷是否能上下滑動,所以要想適配ListView的話要去實現mChildScrollUpCallback.canChildScrollLeft方法

public boolean canChildScrollUp() {
        if (mChildScrollUpCallback != null) {
            return mChildScrollUpCallback.canChildScrollLeft(this, mTarget);
        }
//        if (mTarget instanceof ListView) {
//            return ListViewCompat.canScrollList((ListView) mTarget, -1);
            return mChildScrollUpCallback.canChildScrollLeft(this, mTarget);
//        }
        return mTarget.canScrollHorizontally(-1);
}
    
// NestedScrollingParent
 @Override
 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
     return isEnabled() && !mReturningToStart && !mRefreshing
             && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_HORIZONTAL) != 0;
 }

@Override
public void onNestedScrollAccepted(View child, View target, int axes) {
    // Reset the counter of how much leftover scroll needs to beconsumed.
       mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes);
       // Dispatch up to the nested parent
       startNestedScroll(axes & ViewCompat.SCROLL_AXIS_HORIZONTAL);
       mTotalUnconsumed = 0;
       mNestedScrollInProgress = true;
   }

4.修改完成後試了一下效果感覺下拉組件就是那個圓圈下拉的距離和手指滑動不協調,看下源碼有一個DRAG_RATE(阻尼係數)有一個這個參數改大一點。

參考:

https://www.jianshu.com/p/1f0d44faed5f

https://blog.csdn.net/birthmarkqiqi/article/details/79564289

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章