Android ViewPager2 嵌套 RecyclerView 滑动冲突解决方案

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)都会遵守

相关推荐
火柴就是我8 小时前
让我们实现一个更好看的内部阴影按钮
android·flutter
砖厂小工15 小时前
用 GLM + OpenClaw 打造你的 AI PR Review Agent — 让龙虾帮你审代码
android·github
张拭心15 小时前
春节后,有些公司明确要求 AI 经验了
android·前端·人工智能
张拭心15 小时前
Android 17 来了!新特性介绍与适配建议
android·前端
Kapaseker18 小时前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
黄林晴18 小时前
Android17 为什么重写 MessageQueue
android
阿巴斯甜2 天前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker2 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95272 天前
Andorid Google 登录接入文档
android
黄林晴2 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack