You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

父Fragment与子Fragment嵌套ViewPager2时子ViewPager2滚动异常求助

解决ViewPager2嵌套滚动冲突问题

问题分析

你遇到的是横向父ViewPager2嵌套纵向子ViewPager2的滚动冲突:父ViewPager2会默认拦截横向触摸事件,但当用户在子ViewPager2上进行纵向滑动时,事件可能被父View拦截,导致子ViewPager2滚动异常;而直接禁用父View的用户输入又会导致父ViewPager2无法切换页面。

核心解决方案

通过触摸事件方向判断,动态控制父View是否拦截触摸事件:

  • 当检测到纵向滑动(子ViewPager2需要的方向)时,阻止父View拦截事件,让子View正常处理滚动
  • 当检测到横向滑动(父ViewPager2需要的方向)时,允许父View拦截事件,保证父View可以切换页面

实现方式

方式一:自定义VerticalViewPager2子类

创建专门处理纵向滚动的ViewPager2子类,内置触摸事件判断逻辑:

import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.ViewConfiguration
import androidx.viewpager2.widget.ViewPager2

class VerticalViewPager2(context: Context, attrs: AttributeSet?) : ViewPager2(context, attrs) {
    private val touchSlop = ViewConfiguration.get(context).scaledTouchSlop
    private var startX = 0f
    private var startY = 0f

    override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                startX = event.x
                startY = event.y
                // 初始时请求父View不要拦截
                parent.requestDisallowInterceptTouchEvent(true)
            }
            MotionEvent.ACTION_MOVE -> {
                val dx = event.x - startX
                val dy = event.y - startY
                // 判断滑动方向:纵向滑动且超过触摸阈值时,阻止父拦截;否则允许父拦截
                if (Math.abs(dy) > touchSlop && Math.abs(dy) > Math.abs(dx)) {
                    parent.requestDisallowInterceptTouchEvent(true)
                } else {
                    parent.requestDisallowInterceptTouchEvent(false)
                }
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                // 事件结束后恢复父View的拦截权限
                parent.requestDisallowInterceptTouchEvent(false)
            }
        }
        return super.onInterceptTouchEvent(event)
    }
}

在videoFragment的布局中使用这个自定义View代替原生ViewPager2,并设置纵向方向:

<com.yourpackage.VerticalViewPager2
    android:id="@+id/viewPagerVideo"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" />

方式二:给原生ViewPager2设置触摸监听器

如果不想自定义子类,可以在videoFragment的代码中直接给子ViewPager2添加触摸事件逻辑:

import android.view.MotionEvent
import android.view.ViewConfiguration
import androidx.viewpager2.widget.ViewPager2

// 在videoFragment的onViewCreated中
binding.viewPagerVideo.apply {
    orientation = ViewPager2.ORIENTATION_VERTICAL
    val touchSlop = ViewConfiguration.requireDefault(context).scaledTouchSlop
    var startX = 0f
    var startY = 0f

    setOnTouchListener { v, event ->
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                startX = event.x
                startY = event.y
                v.parent.requestDisallowInterceptTouchEvent(true)
            }
            MotionEvent.ACTION_MOVE -> {
                val dx = event.x - startX
                val dy = event.y - startY
                if (Math.abs(dy) > touchSlop && Math.abs(dy) > Math.abs(dx)) {
                    v.parent.requestDisallowInterceptTouchEvent(true)
                } else {
                    v.parent.requestDisallowInterceptTouchEvent(false)
                }
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                v.parent.requestDisallowInterceptTouchEvent(false)
            }
        }
        // 让ViewPager2处理自身的触摸事件
        super@apply.onTouchEvent(event)
    }
}

原理说明

ViewPager2基于RecyclerView实现,其触摸事件处理逻辑继承自RecyclerView。通过requestDisallowInterceptTouchEvent(true)可以通知父View不要拦截当前的触摸事件流,从而让子ViewPager2能够正常接收纵向滚动事件;当检测到横向滑动时,恢复父View的拦截权限,保证父ViewPager2可以切换页面。

内容的提问来源于stack exchange,提问作者prabhat biswal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 00:39:50