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 群组聊天怎么实现:基于 ZIM 的完整落地指南(附可运行 Demo)
android
三少爷的鞋10 小时前
现代 Android 架构指南:不要再主动设计 Callback 接口
android
TimeFine16 小时前
AI 编码工作流的设计
android·ai编程
骑着蜗牛撵大象32717 小时前
C++20 协程 × 屏障:手写一个 co_await 版 Barrier,让等待不再钉死线程
android·c++20·协程·并发编程·co_await·屏障同步
山东孙燕姿18 小时前
设备台账重构:从一张表到三层模型
android·java·网络·低代码·重构·rxjava
蒸鱼Yuzheng19 小时前
移动端 CPU 调度分析:线程亲和性、大小核迁移与卡顿
android·perfetto·性能分析·线程优化·cpu调度
booboosui19 小时前
安卓唤醒词:12 维 MFCC 加 DTW,阈值 1.8
android
传奇开心果19 小时前
Compose Multiplatform 共享边界实战:架构契约、互操作同步与可回退设计
android·kotlin
事圆则缓20 小时前
从开机到首帧:Android 系统与应用启动流程源码分析
android
AI吃大瓜20 小时前
指针压力表读数4:Android实现指针压力表读数(可实时检测)
android·指针读数·指针压力表·压力表·压力表读数