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

相关推荐
黄林晴3 小时前
Google Play 发版链路全面重构:合规前置、审核自动化、生态全面收紧
android·google
通玄4 小时前
Jetpack Compose 入门系列(四):动画基本使用
android
杉氧4 小时前
Kotlin 协程深度解析②:生存指南——掌握结构化并发的生命线
android·kotlin
故渊at4 小时前
第四板块:Android 输入系统与触控事件 | 第十五篇:InputReader 与 InputDispatcher 的触控流水线
android·anr·输入系统·inputdispatcher·inputreader·触控事件·inputevent
方白羽4 小时前
Vibe Coding 四个核心阶段
android·前端·app
潘潘潘6 小时前
Android网络结构分析——有线网络
android
踏雪羽翼7 小时前
Android OpenGL实现十几种美颜功能
android
Android小码家8 小时前
BootAnimation+SE+开机MP4动画播放
android·framework
加农炮手Jinx8 小时前
Flutter for OpenHarmony:pub_updater 命令行工具自动更新专家(DevOps 运维必备) 深度解析与鸿蒙适配指南
android·运维·网络·flutter·华为·harmonyos·devops