kunfei 3 лет назад
Родитель
Сommit
9c58384f76

+ 122 - 0
app/src/main/java/io/legado/app/ui/widget/recycler/ViewPager2Container.kt

@@ -0,0 +1,122 @@
+package io.legado.app.ui.widget.recycler
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.widget.RelativeLayout
+import androidx.viewpager2.widget.ViewPager2
+import kotlin.math.abs
+
+@Suppress("unused")
+class ViewPager2Container @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0
+) : RelativeLayout(context, attrs, defStyleAttr) {
+
+    private var mViewPager2: ViewPager2? = null
+    private var disallowParentInterceptDownEvent = true
+    private var startX = 0
+    private var startY = 0
+
+    override fun onFinishInflate() {
+        super.onFinishInflate()
+        for (i in 0 until childCount) {
+            val childView = getChildAt(i)
+            if (childView is ViewPager2) {
+                mViewPager2 = childView
+                break
+            }
+        }
+        if (mViewPager2 == null) {
+            throw IllegalStateException("The root child of ViewPager2Container must contains a ViewPager2")
+        }
+    }
+
+    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
+        val doNotNeedIntercept = (!mViewPager2!!.isUserInputEnabled
+                || (mViewPager2?.adapter != null
+                && mViewPager2?.adapter!!.itemCount <= 1))
+        if (doNotNeedIntercept) {
+            return super.onInterceptTouchEvent(ev)
+        }
+        when (ev.action) {
+            MotionEvent.ACTION_DOWN -> {
+                startX = ev.x.toInt()
+                startY = ev.y.toInt()
+                parent.requestDisallowInterceptTouchEvent(!disallowParentInterceptDownEvent)
+            }
+            MotionEvent.ACTION_MOVE -> {
+                val endX = ev.x.toInt()
+                val endY = ev.y.toInt()
+                val disX = abs(endX - startX)
+                val disY = abs(endY - startY)
+                if (mViewPager2!!.orientation == ViewPager2.ORIENTATION_VERTICAL) {
+                    onVerticalActionMove(endY, disX, disY)
+                } else if (mViewPager2!!.orientation == ViewPager2.ORIENTATION_HORIZONTAL) {
+                    onHorizontalActionMove(endX, disX, disY)
+                }
+            }
+            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> parent.requestDisallowInterceptTouchEvent(
+                false
+            )
+        }
+        return super.onInterceptTouchEvent(ev)
+    }
+
+    private fun onHorizontalActionMove(endX: Int, disX: Int, disY: Int) {
+        if (mViewPager2?.adapter == null) {
+            return
+        }
+        if (disX > disY) {
+            val currentItem = mViewPager2?.currentItem
+            val itemCount = mViewPager2?.adapter!!.itemCount
+            if (currentItem == 0 && endX - startX > 0) {
+                parent.requestDisallowInterceptTouchEvent(false)
+            } else {
+                parent.requestDisallowInterceptTouchEvent(
+                    currentItem != itemCount - 1
+                            || endX - startX >= 0
+                )
+            }
+        } else if (disY > disX) {
+            parent.requestDisallowInterceptTouchEvent(false)
+        }
+    }
+
+    private fun onVerticalActionMove(endY: Int, disX: Int, disY: Int) {
+        if (mViewPager2?.adapter == null) {
+            return
+        }
+        val currentItem = mViewPager2?.currentItem
+        val itemCount = mViewPager2?.adapter!!.itemCount
+        if (disY > disX) {
+            if (currentItem == 0 && endY - startY > 0) {
+                parent.requestDisallowInterceptTouchEvent(false)
+            } else {
+                parent.requestDisallowInterceptTouchEvent(
+                    currentItem != itemCount - 1
+                            || endY - startY >= 0
+                )
+            }
+        } else if (disX > disY) {
+            parent.requestDisallowInterceptTouchEvent(false)
+        }
+    }
+
+    /**
+     * 设置是否允许在当前View的{@link MotionEvent#ACTION_DOWN}事件中禁止父View对事件的拦截,该方法
+     * 用于解决CoordinatorLayout+CollapsingToolbarLayout在嵌套ViewPager2Container时引起的滑动冲突问题。
+     *
+     * 设置是否允许在ViewPager2Container的{@link MotionEvent#ACTION_DOWN}事件中禁止父View对事件的拦截,该方法
+     * 用于解决CoordinatorLayout+CollapsingToolbarLayout在嵌套ViewPager2Container时引起的滑动冲突问题。
+     *
+     * @param disallowParentInterceptDownEvent 是否允许ViewPager2Container在{@link MotionEvent#ACTION_DOWN}事件中禁止父View拦截事件,默认值为false
+     *   true 不允许ViewPager2Container在{@link MotionEvent#ACTION_DOWN}时间中禁止父View的时间拦截,
+     *   设置disallowIntercept为true可以解决CoordinatorLayout+CollapsingToolbarLayout的滑动冲突
+     *   false 允许ViewPager2Container在{@link MotionEvent#ACTION_DOWN}时间中禁止父View的时间拦截,
+     */
+    fun disallowParentInterceptDownEvent(disallowParentInterceptDownEvent: Boolean) {
+        this.disallowParentInterceptDownEvent = disallowParentInterceptDownEvent
+    }
+}