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

相关推荐
恋猫de小郭21 小时前
Dart 3.13 的到底改了什么?为什么很重要?有什么坑?
android·前端·flutter
HZZD_HZZD21 小时前
3T-UEM 数据建模实战:三维立方体 + LAM/ELA 双归因怎么落地?
android
Carson带你学Android1 天前
腾讯正式上线AI应用生成平台:一句话生成 App,还能直接上架商店
android·ai编程
小陈的进阶之路1 天前
Claude Code辅助测试:API测试与pytest自动化
android·开发语言·kotlin
三少爷的鞋1 天前
Kotlin 与 Java,不是简单的高低之分
android
一笑的小酒馆1 天前
Android12Launcher3实现应用裁剪
android
FinelyYang1 天前
UniApp + LiveKit:Android 端为什么要用原生做屏幕共享,以及我们怎么落地的
android·uni-app
蓝速科技1 天前
蓝速科技信创落地:平衡安全合规与项目成本的实战方案
android·运维·人工智能·科技·安全·电脑·鸿蒙
又见情义2 天前
RK3568 Android 13 SDK 开机自动开启共享热点实践
android
mmsx2 天前
return false 不是拦截:一次按键触发两个动作的事件冒泡陷阱
android·bug