美文网首页
ViewPager2 嵌套 ViewPager2滑动冲突问题解决

ViewPager2 嵌套 ViewPager2滑动冲突问题解决

作者: 善良的老农 | 来源:发表于2024-08-15 15:30 被阅读0次

xml布局如下:

<androidx.viewpager2.integration.testapp.NestedScrollableHost

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_marginTop="8dp">

<androidx.viewpager2.widget.ViewPager2

android:id="@+id/viewPager2"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

    </androidx.viewpager2.integration.testapp.NestedScrollableHost>

自定义View:  NestedScrollableHost

/*

* Copyright 2019 The Android Open Source Project

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

*      http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

package androidx.viewpager2.integration.testapp

import android.content.Context

import android.util.AttributeSet

import android.view.MotionEvent

import android.view.View

import android.view.ViewConfiguration

import android.widget.FrameLayout

import androidx.viewpager2.widget.ViewPager2

import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL

import kotlin.math.absoluteValue

import kotlin.math.sign

/**

* Layout to wrap a scrollable component inside a ViewPager2. Provided as a solution to the problem

* where pages of ViewPager2 have nested scrollable elements that scroll in the same direction as

* ViewPager2. The scrollable element needs to be the immediate and only child of this host layout.

*

* This solution has limitations when using multiple levels of nested scrollable elements

* (e.g. a horizontal RecyclerView in a vertical RecyclerView in a horizontal ViewPager2).

*/

class NestedScrollableHost : FrameLayout {

    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

    private var touchSlop = 0

    private var initialX = 0f

    private var initialY = 0f

    private val parentViewPager: ViewPager2?

        get() {

            var v: View? = parent as? View

            while (v != null && v !is ViewPager2) {

                v = v.parent as? View

            }

            return v as? ViewPager2

        }

    private val child: View? get() = if (childCount > 0) getChildAt(0) else null

    init {

        touchSlop = ViewConfiguration.get(context).scaledTouchSlop

    }

    private fun canChildScroll(orientation: Int, delta: Float): Boolean {

        val direction = -delta.sign.toInt()

        return when (orientation) {

            0 -> child?.canScrollHorizontally(direction) ?: false

            1 -> child?.canScrollVertically(direction) ?: false

            else -> throw IllegalArgumentException()

        }

    }

    override fun onInterceptTouchEvent(e: MotionEvent): Boolean {

        handleInterceptTouchEvent(e)

        return super.onInterceptTouchEvent(e)

    }

    private fun handleInterceptTouchEvent(e: MotionEvent) {

        val orientation = parentViewPager?.orientation ?: return

        // Early return if child can't scroll in same direction as parent

        if (!canChildScroll(orientation, -1f) && !canChildScroll(orientation, 1f)) {

            return

        }

        if (e.action == MotionEvent.ACTION_DOWN) {

            initialX = e.x

            initialY = e.y

            parent.requestDisallowInterceptTouchEvent(true)

        } else if (e.action == MotionEvent.ACTION_MOVE) {

            val dx = e.x - initialX

            val dy = e.y - initialY

            val isVpHorizontal = orientation == ORIENTATION_HORIZONTAL

            // assuming ViewPager2 touch-slop is 2x touch-slop of child

            val scaledDx = dx.absoluteValue * if (isVpHorizontal) .5f else 1f

            val scaledDy = dy.absoluteValue * if (isVpHorizontal) 1f else .5f

            if (scaledDx > touchSlop || scaledDy > touchSlop) {

                if (isVpHorizontal == (scaledDy > scaledDx)) {

                    // Gesture is perpendicular, allow all parents to intercept

                    parent.requestDisallowInterceptTouchEvent(false)

                } else {

                    // Gesture is parallel, query child if movement in that direction is possible

                    if (canChildScroll(orientation, if (isVpHorizontal) dx else dy)) {

                        // Child can scroll, disallow all parents to intercept

                        parent.requestDisallowInterceptTouchEvent(true)

                    } else {

                        // Child cannot scroll, allow all parents to intercept

                        parent.requestDisallowInterceptTouchEvent(false)

                    }

                }

            }

        }

    }

}

其他滑动事件处理可以子ViewPager2 在外层包裹

<androidx.core.widget.NestedScrollView

        android:id="@+id/nestedScrollView"

        android:layout_width="match_parent"

        android:layout_height="match_parent">

    <androidx.viewpager2.integration.testapp.NestedScrollableHost

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        >

        <androidx.viewpager2.widget.ViewPager2

            android:id="@+id/viewPager2"

            android:layout_width="match_parent"

            android:layout_height="wrap_content" />

    </androidx.viewpager2.integration.testapp.NestedScrollableHost>

    </androidx.core.widget.NestedScrollView>

相关文章

网友评论

      本文标题:ViewPager2 嵌套 ViewPager2滑动冲突问题解决

      本文链接:https://www.haomeiwen.com/subject/qruekjtx.html