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

相关推荐
Libraeking2 小时前
破壁行动:在旧项目中丝滑嵌入 Compose(混合开发实战)
android·经验分享·android jetpack
市场部需要一个软件开发岗位3 小时前
JAVA开发常见安全问题:Cookie 中明文存储用户名、密码
android·java·安全
JMchen1235 小时前
Android后台服务与网络保活:WorkManager的实战应用
android·java·网络·kotlin·php·android-studio
crmscs5 小时前
剪映永久解锁版/电脑版永久会员VIP/安卓SVIP手机永久版下载
android·智能手机·电脑
localbob5 小时前
杀戮尖塔 v6 MOD整合版(Slay the Spire)安卓+PC端免安装中文版分享 卡牌肉鸽神作!杀戮尖塔中文版,电脑和手机都能玩!杀戮尖塔.exe 杀戮尖塔.apk
android·杀戮尖塔apk·杀戮尖塔exe·游戏分享
机建狂魔5 小时前
手机秒变电影机:Blackmagic Camera + LUT滤镜包的专业级视频解决方案
android·拍照·摄影·lut滤镜·拍摄·摄像·录像
hudawei9965 小时前
flutter和Android动画的对比
android·flutter·动画
lxysbly7 小时前
md模拟器安卓版带金手指2026
android
儿歌八万首8 小时前
硬核春节:用 Compose 打造“赛博鞭炮”
android·kotlin·compose·春节
消失的旧时光-194311 小时前
从 Kotlin 到 Dart:为什么 sealed 是处理「多种返回结果」的最佳方式?
android·开发语言·flutter·架构·kotlin·sealed