可以下拉刷新、上拉获取更多的SwipeRefreshAndLoadLayout

转载自 http://nobugs.sinaapp.com/?p=1286

SwipeRefreshLayout增加上拉加载更多,只需处理3个方法

1. 增加canChildScrollDown(),判断是否可以上拉
2. 增加底部上拉view距离
3. 增加onLoadMore接口

什么时候触发SwipeRefreshLayout的上拉

当view可以上拉的时候,不触发SwipeRefreshLayout的上拉;
当view不能上拉的时候,触发SwipeRefreshLayout的上拉;
所以增加canChildScrollDown()来判断view是否可以上拉。

    /**
     * < 14 的没有测试,所以注释掉了,暂时不支持.
     * @return Whether it is possible for the child view of this layout to
     * scroll down. Override this if the child view is a custom view.
     */
    public boolean canChildScrollDown() {
            if (android.os.Build.VERSION.SDK_INT < 14) {
                return true;//don't support < 14
//                if (mTarget instanceof AbsListView) {
//                    final AbsListView absListView = (AbsListView) mTarget;
//                    return absListView.getChildCount() > 0
//                            && (absListView.getLastVisiblePosition() == absListView.getAdapter().getCount() - 1
//                            || absListView.getChildAt(absListView.getLastVisiblePosition() - 1)
//                                    .getBottom() < absListView.getPaddingBottom());
//                } else {
//                    return mTarget.getScrollY() < 0;
//                }
            } else {
                return ViewCompat.canScrollVertically(mTarget, 1);
            }
        }



底部上拉view距离

1. onInterceptTouchEvent()处理是否拦截滚动事件(不能上拉赫下拉的时候,拦截)
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    ensureTarget();
    boolean handled = false;
    if (mReturningToStart && ev.getAction() == MotionEvent.ACTION_DOWN) {
        mReturningToStart = false;
    }
    if (!mRefreshing && isEnabled() && !mReturningToStart && mMode.permitsPullToRefresh()
            && (!canChildScrollUp() || !canChildScrollDown())) {
        handled = onTouchEvent(ev);//增加!canChildScrollDown() 判断
    }
    return !handled ? super.onInterceptTouchEvent(ev) : handled;
}


2. 计算上拉的距离
@Override
public boolean onTouchEvent(MotionEvent event) {
    final int action = event.getAction();
    boolean handled = false;
    switch (action) {
        case MotionEvent.ACTION_DOWN:
            ...
        case MotionEvent.ACTION_MOVE:
            if (mDownEvent != null && !mReturningToStart) {
                final float eventY = event.getY();
                float yDiff = eventY - mDownEvent.getY();
                if(!canChildScrollUp() && yDiff > 0 && mMode.permitsPullFromStart()){
                    mCurrentMode = Mode.PULL_FROM_START;
                } else if (!canChildScrollDown() && yDiff < 0 && mMode.permitsPullFromEnd()) {
                    mCurrentMode = Mode.PULL_FROM_END;
                    yDiff = -yDiff;//上拉计算的距离是负数,先设置为正数,后面再取负数.
                } else {
                    yDiff = 0;//对于其他情况,不能上拉和下拉
                }

                if (yDiff > mTouchSlop) {
                    // User velocity passed min velocity; trigger a refresh
                    if (yDiff > mDistanceToTriggerSync) {
                        // User movement passed distance; trigger a refresh
                        if(mCurrentMode == Mode.PULL_FROM_START){
                            startRefresh();//下拉刷新
                        } else if(mCurrentMode == Mode.PULL_FROM_END){
                            startLoadMore();//加载更多
                        }
                        handled = true;
                        break;
                    } else {
                        // Just track the user's movement
                        setTriggerPercentage(
                                mAccelerateInterpolator.getInterpolation(
                                        yDiff / mDistanceToTriggerSync)
                        );
                        float offsetTop = yDiff;
                        if (mPrevY > eventY) {
                            offsetTop = yDiff - mTouchSlop;
                        }
                        updateContentOffsetTop((int) (offsetTop));
                        if ((mCurrentMode == Mode.PULL_FROM_START && mPrevY > eventY && (mTarget.getTop() < mTouchSlop))
                                || (mCurrentMode == Mode.PULL_FROM_END && mPrevY < eventY
                                        && (mTarget.getBottom() - mHeight < mTouchSlop))) {
                            // If the user puts the view back at the top, we
                            // don't need to. This shouldn't be considered
                            // cancelling the gesture as the user can restart from the top.
                            removeCallbacks(mCancel);//当用户回退的时候,直接取消动作
                        } else {
                           updatePositionTimeout();//当用户300ms没有完成上拉或者下拉,直接复位
                        }
                        mPrevY = event.getY();
                        handled = true;
                    }
                }
            }
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            if (mDownEvent != null) {
                mDownEvent.recycle();
                mDownEvent = null;
            }
            break;
    }
    return handled;
}


3. updateContentOffsetTop()位置
private void updateContentOffsetTop(int targetTop) {
    final int currentTop = mTarget.getTop();
    final int currentBottom = mTarget.getBottom() - mHeight;
    if(!canChildScrollUp() && mCurrentMode == Mode.PULL_FROM_START){
        if (targetTop > mDistanceToTriggerSync) {
            targetTop = (int) mDistanceToTriggerSync;
        }else if (targetTop < 0){
            targetTop = 0;
        }
        setTargetOffsetTopAndBottom(targetTop - currentTop);
    } else {
        if (targetTop > mDistanceToTriggerSync) {
            targetTop = (int) mDistanceToTriggerSync;
        }else if (targetTop < 0){
            targetTop = 0;
        }
        setTargetOffsetTopAndBottom((-targetTop - currentBottom));//-targetTop是个负数,让view向上移动
    }
}


onLoadMore接口

/**
 * Classes that wish to be notified when the swipe gesture correctly
 * triggers a refresh or load more should implement this interface.
 */
public interface OnRefreshListener {
    public void onRefresh();
    public void onLoadMore();
}


提示:非ListView的使用,需要加个ScrollView

<com.dahuo.learn.swiperefreshandload.view.SwipeRefreshAndLoadLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/swipe_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/app_name" />
    </ScrollView>
</com.dahuo.learn.swiperefreshandload.view.SwipeRefreshAndLoadLayout>

提示:默认只打开了下拉刷新,可以设置模式

mSwipeLayout.setmMode(SwipeRefreshAndLoadLayout.Mode.BOTH); 






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值