
1.异常:
日常开发过程中,或多或少的会遇到多层ViewPager和ViewPager2嵌套RecyclerView的情况,当这种嵌套出现的时候会遇到,同方的vp或者vp2同RecycleView滑动冲突,RecycleView的滑动事件会被上层的触摸事件拦截掉.
大白话:嵌套导致收拾冲突
2.解决方案:
- 在跟布局重写事件拦截分发(
贼麻烦,但好使,且灵活
) - 子布局通知父布局别拦截我(
特定场景
)
3.实现:
自定义Rv
kotlin
package com.qianrun.live.fragment.follow.play.ui
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import androidx.recyclerview.widget.RecyclerView
import kotlin.math.abs
/**
*
*@Author: wkq
*
*@Time: 2025/9/15 15:55
*
*@Desc:
*/
class HorizontalRecyclerView(context: Context, attrs: AttributeSet? = null) : RecyclerView(context, attrs) {
private var startX = 0f
private var startY = 0f
override fun onInterceptTouchEvent(e: MotionEvent): Boolean {
when (e.actionMasked) {
MotionEvent.ACTION_DOWN -> {
startX = e.x
startY = e.y
parent.requestDisallowInterceptTouchEvent(true)
}
MotionEvent.ACTION_MOVE -> {
val dx = e.x - startX
val dy = e.y - startY
if (abs(dx) > abs(dy)) {
// 横向滑动
if ((dx > 0 && isAtStart()) || (dx < 0 && isAtEnd())) {
// 已到头尾,让父控件拦截滑动
parent.requestDisallowInterceptTouchEvent(false)
} else {
parent.requestDisallowInterceptTouchEvent(true)
}
} else {
// 纵向滑动让父控件处理
parent.requestDisallowInterceptTouchEvent(false)
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
parent.requestDisallowInterceptTouchEvent(false)
}
}
return super.onInterceptTouchEvent(e)
}
private fun isAtStart(): Boolean {
return !canScrollHorizontally(-1) // true 表示已经到最左
}
private fun isAtEnd(): Boolean {
return !canScrollHorizontally(1) // true 表示已经到最右
}
}
设置 LayoutManager
ini
binding.rvHotContent.apply {
layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
isNestedScrollingEnabled = true
}
4.核心方法说明
4.1:开启嵌套滚动的效果
rv.setNestedScrollingEnabled(boolean enabled)
-
作用:开启或关闭子控件向父控件报告滚动的能力
-
参数:
enabled = true
→ 开启嵌套滚动enabled = false
→ 关闭嵌套滚动
4.2:是 Android 触摸事件分发机制 中的一个关键方法,用于控制 父控件是否拦截子控件的触摸事件
parent.requestDisallowInterceptTouchEvent(true)
-
true → 请求父控件 不要拦截 当前触摸事件,子控件自己处理
-
false → 允许父控件拦截触摸事件
-
注意:父控件可以选择忽略这个请求,但大部分标准控件(如 ViewPager2、ScrollView)都会遵守