AppBarLayout内设置nestedScrollingEnabled无效,如何避免横向滑动触发下拉刷新
问题原因
你设置nestedScrollingEnabled = false不生效,是因为SwipeRefreshLayout的下拉刷新触发逻辑和嵌套滑动机制是相互独立的:
- SwipeRefreshLayout的下拉判断是在
onInterceptTouchEvent阶段完成的,只要检测到竖向滑动距离达到阈值就会拦截事件触发刷新,不管子View是不是正在处理横向滑动 - 关闭RecyclerView的嵌套滑动,只会让RecyclerView不参与嵌套滑动分发流程,不会影响SwipeRefreshLayout的触摸事件拦截逻辑,所以完全起不到防止误触的效果。
可行解决方案
方案1:自定义SwipeRefreshLayout(最稳定,适配性最高)
重写SwipeRefreshLayout的触摸拦截逻辑,判断到当前手势为横向滑动时不拦截事件,直接交给子View处理,代码实现如下:
class NonInterceptSwipeRefreshLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null ) : SwipeRefreshLayout(context, attrs) { private val touchSlop = ViewConfiguration.get(context).scaledTouchSlop private var downX = 0f private var downY = 0f private var isHorizontalDragging = false override fun onInterceptTouchEvent(event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { downX = event.x downY = event.y isHorizontalDragging = false } MotionEvent.ACTION_MOVE -> { val dx = kotlin.math.abs(event.x - downX) val dy = kotlin.math.abs(event.y - downY) // 横向滑动距离大于竖向且达到滑动阈值,判定为横向滑动 if (dx > touchSlop && dx > dy) { isHorizontalDragging = true return false } } } // 仅非横向滑动场景走原生拦截逻辑 return if (isHorizontalDragging) false else super.onInterceptTouchEvent(event) } }
直接把布局文件中原生的SwipeRefreshLayout替换为这个自定义类即可,不需要修改其他业务逻辑。
方案2:给横向RecyclerView添加触摸拦截
如果你不想自定义View,可以直接给横向RecyclerView设置触摸监听,检测到横向滑动时主动请求父布局不拦截事件:
var downX = 0f var downY = 0f val touchSlop = ViewConfiguration.get(this).scaledTouchSlop horizontalRecyclerView.setOnTouchListener { view, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { downX = event.x downY = event.y } MotionEvent.ACTION_MOVE -> { val dx = kotlin.math.abs(event.x - downX) val dy = kotlin.math.abs(event.y - downY) if (dx > touchSlop && dx > dy) { view.parent.requestDisallowInterceptTouchEvent(true) } } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { view.parent.requestDisallowInterceptTouchEvent(false) } } false }
方案3:禁用顶部联动(适配无联动需求的场景)
如果你的页面不需要AppBarLayout和下方滚动区域的联动效果,可以直接给AppBarLayout设置app:layout_behavior="@null",同时给横向RecyclerView设置isNestedScrollingEnabled = false,也能解决滑动冲突,该方案适配场景有限,仅适合无顶部滚动联动需求的页面。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

