可以下拉刷新、上拉获取更多的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
    评论
### 回答1: 实现下拉刷新上拉加载多的话,你可以使用Compose中的`SwipeRefreshLayout`和`LazyColumnFor`。 `SwipeRefreshLayout`可以用来实现下拉刷新,它可以包含其他的Compose控件,并且在用户下拉时会触发刷新事件。 而`LazyColumnFor`是一个可懒加载的Column,它会根据屏幕的空间加载多的item,这样可以实现上拉加载多的效果。 以下是一个简单的示例代码: ``` @Composable fun RefreshableList(data: List<String>) { SwipeRefreshLayout(refreshing = state.refreshing) { LazyColumnFor(data) { item -> Text(item) } } } ``` 在这段代码中,`SwipeRefreshLayout`包含了一个`LazyColumnFor`,而`LazyColumnFor`则根据传入的`data`生成了若干个`Text`控件,当用户下拉时会触发刷新事件,并且根据屏幕的空间自动加载多。 ### 回答2: compose 是一种用于构建用户界面的声明式工具集,可以通过函数式编程方式来创建可组合的UI组件。要实现下拉刷新上拉加载多功能,可以借助 compose 提供的布局组件和手势监听等功能。 首先,可以使用 compose 的 LazyColumn 组件来展示列表数据,并且添加一个监听手势的方法,以实现下拉刷新上拉加载多的功能。 下拉刷新的实现可以通过监听手势的位置变化,当手指位置向下滑动一定距离之后,可以通过修改列表数据源来触发刷新操作。 上拉加载多的实现可以通过监听手势的位置变化,当手指位置向上滑动一定距离之后,可以通过加载多数据并添加到列表数据源的方式来触发加载多操作。 在代码中,可以使用 onGragGesture 方法监听手势的位置变化,通过判断手势状态来执行相应的刷新和加载逻辑。 具体的实现流程如下: 1. 创建一个列表数据源列表,用于展示列表数据。 2. 使用 LazyColumn 组件来展示列表数据,并添加 onGragGesture 方法监听手势。 3. 在 onGragGesture 方法中,根据手指位置的变化和手势状态的变化来执行对应的刷新和加载逻辑。 4. 当手势状态变为 Dragging,并且手指位置向下滑动一定距离时,触发下拉刷新操作。可以通过修改列表数据源并新列表进行刷新操作。 5. 当手势状态变为 Dragging,并且手指位置向上滑动一定距离时,触发上拉加载多操作。可以通过加载多数据并添加到列表数据源的方式来实现加载多功能。 通过上述步骤,可以使用 compose 来实现下拉刷新上拉加载多功能。使用 compose 提供的布局组件和手势监听等功能,可以轻松实现用户界面的交互。 ### 回答3: 使用compose实现下拉刷新上拉加载多的过程如下: 1. 首先,在页面组件中定义一个状态变量,用于表示当前的刷新和加载多的状态。 2. 使用useCallback或者useState来定义一个函数,用于处理下拉刷新的逻辑。 3. 在页面组件中,使用useEffect来监听下拉刷新的事件,一旦触发下拉刷新事件,就调用上一步定义的处理函数。 4. 在页面组件中,使用useEffect监听滚动事件。一旦滚动到页面底部,就触发加载多的逻辑。 5. 使用条件渲染来根据不同的状态显示不同的内容,例如加载中、加载失败等。 6. 使用ScrollView组件或者FlatList组件来渲染长列表,并包裹上拉加载多的内容。 7. 在加载多的逻辑处理函数中,新列表数据,将新的数据追加到原有的数据列表中,以实现加载多的效果。 8. 在下拉刷新的逻辑处理函数中,重置列表数据,重新加载最新的数据,以实现下拉刷新的效果。 以上就是使用compose实现下拉刷新上拉加载多的基本步骤。具体的实现代码可以根据具体的场景和需求来灵活调整。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值