如何修改原生SwipeRefreshLayout实现底部上拉刷新而无需引入第三方库
原生SwipeRefreshLayout修改实现上拉底部刷新方案
核心改造逻辑
无需对整个布局或者子View做旋转处理,仅需要修改3处核心逻辑即可实现:1. 子View滚动边界的判断逻辑反转;2. 触摸滑动方向的触发条件反转;3. 刷新指示器的位置调整到底部。
具体实现步骤
第一步:自定义类继承
SwipeRefreshLayout,重写滚动边界判断方法
原生canChildScrollUp方法用来判断子View是否滚动到顶部,未滚动到顶部时拦截下拉事件,我们将其改为判断子View是否滚动到底部,未滚动到底部时拦截上拉事件:override fun canChildScrollUp(): Boolean { val childView = getChildAt(0) ?: return super.canChildScrollUp() // canScrollVertically(1) 返回true代表子View还能向下滚动,即未到达底部 return childView.canScrollVertically(1) }第二步:调整刷新指示器的显示位置
重写onLayout方法,将原生顶部的刷新指示器移动到布局底部,可选择旋转指示器适配上拉交互的视觉逻辑:init { // 旋转指示器,让箭头方向适配上拉操作 val progressView = findViewById<View>(androidx.swiperefreshlayout.R.id.swipe_refresh_progress) progressView.rotation = 180f } override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { super.onLayout(changed, left, top, right, bottom) val progressView = findViewById<View>(androidx.swiperefreshlayout.R.id.swipe_refresh_progress) val params = progressView.layoutParams as MarginLayoutParams // 将指示器的topMargin设为布局高度减去自身高度,固定在底部 params.topMargin = measuredHeight - progressView.measuredHeight progressView.layoutParams = params }第三步:修改触摸事件的滑动触发逻辑
重写onTouchEvent方法,将原生向下滑动的触发判断反转,改为向上滑动距离超过阈值时触发刷新:private var initialDownY = 0f private val touchSlop = ViewConfiguration.get(context).scaledTouchSlop private var isBeingDragged = false override fun onTouchEvent(ev: MotionEvent): Boolean { when (ev.action) { MotionEvent.ACTION_DOWN -> { initialDownY = ev.y isBeingDragged = false } MotionEvent.ACTION_MOVE -> { val dy = initialDownY - ev.y if (dy > touchSlop && !isBeingDragged && !canChildScrollUp()) { isBeingDragged = true } if (isBeingDragged) { // 原生滑动距离计算逻辑反转,传入向上滑动的距离更新指示器进度 setProgressViewOffset(false, 0, (dy * 0.5f).toInt()) isRefreshing = dy > triggerDistance } } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { isBeingDragged = false } } return isBeingDragged || super.onTouchEvent(ev) }以上代码为Kotlin版本,Java实现逻辑完全一致,仅语法存在差异。
注意事项
- 原生
setOnRefreshListener回调可直接使用,无需额外适配 - 触发阈值直接复用SwipeRefreshLayout原生的
triggerDistance变量,保证交互手感和原生下拉刷新一致 - 该改造仅修改触发逻辑和指示器位置,不会影响内部子View的滚动、点击等交互逻辑
内容的提问来源于stack exchange,提问作者Ahmad Sattout
相关产品推荐
相关产品推荐

