ViewPager2 嵌套 ViewPager2滑動沖突問題解決

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>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末叁扫,一起剝皮案震驚了整個濱河市胎许,隨后出現(xiàn)的幾起案子碰纬,更是在濱河造成了極大的恐慌,老刑警劉巖芽突,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件度苔,死亡現(xiàn)場離奇詭異音诫,居然都是意外死亡攻泼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門诡延,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滞欠,“玉大人,你說我怎么就攤上這事肆良∩歌担” “怎么了逸绎?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長夭谤。 經(jīng)常有香客問我棺牧,道長,這世上最難降的妖魔是什么沮翔? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任陨帆,我火速辦了婚禮曲秉,結(jié)果婚禮上采蚀,老公的妹妹穿的比我還像新娘。我一直安慰自己承二,他們只是感情好榆鼠,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著亥鸠,像睡著了一般妆够。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上负蚊,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天神妹,我揣著相機與錄音,去河邊找鬼家妆。 笑死鸵荠,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的伤极。 我是一名探鬼主播蛹找,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼哨坪!你這毒婦竟也來了庸疾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤当编,失蹤者是張志新(化名)和其女友劉穎届慈,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忿偷,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡金顿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了牵舱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片串绩。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖芜壁,靈堂內(nèi)的尸體忽然破棺而出礁凡,到底是詐尸還是另有隱情高氮,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布顷牌,位于F島的核電站剪芍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏窟蓝。R本人自食惡果不足惜罪裹,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望运挫。 院中可真熱鬧状共,春花似錦、人聲如沸谁帕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽匈挖。三九已至碾牌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間儡循,已是汗流浹背舶吗。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留择膝,地道東北人誓琼。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像调榄,于是被迫代替她去往敵國和親踊赠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容