SlidingPaneLayout 消耗边缘触摸

问题描述 投票:0回答:1

我在

SlidingPaneLayout
中有两个片段,片段 A 和片段 B。片段 A 是主片段,片段 B 是可以滑入的窗格。在无法同时容纳片段 A 和片段 B 的设备上,有一个奇怪的问题行为。如果用户打开片段 B 并尝试点击片段 B 左边缘的任何视图,则触摸会被
SlidingPaneLayout
消耗。这实质上使片段 B 的整个左边缘成为死区,并干扰某些 UI 元素,例如工具栏的向上按钮,因为它位于左边缘附近。它还会干扰底部工具栏的操作按钮。有谁知道为什么会发生这种情况以及如何禁用这种行为?

android androidx slidingpanelayout
1个回答
0
投票

我找出了这个问题的原因,或者至少我找出了导致这种情况发生的代码。我仍然不知道为什么会出现导致此问题的代码。

看起来如果窗格打开

SlidingPaneLayout
会启用
ViewDragHelper
上的边缘跟踪。如果视图是 LTR,则启用左侧边缘跟踪。如果视图是 RTL,则它会启用右侧的边缘跟踪。我不知道为什么
SlidingPaneLayout
会这样做,但我可以在它的源代码中看到这个逻辑。

SlidingPaneLayout
的源代码来看,似乎没有一种简单的方法可以切换此行为。它本质上是硬编码为始终开启的。

为了解决这个问题,我必须延长

SlidingPaneLayout
。然后我覆盖
onInterceptTouchEvent()
并调用
SlidingPaneLayout
onInterceptTouchEvent()
。如果返回 false,则返回 false。如果返回 true,我会检查窗格是否打开。如果是,我检查触摸事件是否发生在左边缘(如果是 LTR)或右边缘(如果是 RTL)。如果触摸发生在边缘,那么我返回 false。否则我返回 true。

这有效地防止了

SlidingPaneLayout
吃掉边缘触摸事件。

固定

SlidingPaneLayout
的完整代码在这里:

class FixedSlidingPaneLayout : SlidingPaneLayout {

    companion object {
        private val sEdgeSizeUsingSystemGestureInsets = Build.VERSION.SDK_INT >= 29
    }

    // We only construct a drag helper to get the width of the drag region.
    private val dragHelper = ViewDragHelper.create(
        this, 0.5f,
        object : ViewDragHelper.Callback() {
            override fun tryCaptureView(child: View, pointerId: Int): Boolean {
                return false
            }
        },
    )

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

    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        val intercept = super.onInterceptTouchEvent(ev)

        if (ev == null) {
            return intercept
        }

        if (!intercept) {
            return false
        }

        if (!isOpen || !isSlideable) {
            return true
        }

        val gestureInsets = getSystemGestureInsets()
            ?: return true

        val edgeSize = max(dragHelper.defaultEdgeSize, gestureInsets.left)

        val isLayoutRtl = isLayoutRtlSupport()

        if (isLayoutRtl) {
            if (ev.x > edgeSize) {
                return false
            }
        } else {
            if (ev.x < edgeSize) {
                return false
            }
        }

        return true
    }

    private fun getSystemGestureInsets(): Insets? {
        var gestureInsets: Insets? = null
        if (sEdgeSizeUsingSystemGestureInsets) {
            val rootInsetsCompat = ViewCompat.getRootWindowInsets(this)
            if (rootInsetsCompat != null) {
                gestureInsets = rootInsetsCompat.systemGestureInsets
            }
        }
        return gestureInsets
    }

    private fun isLayoutRtlSupport(): Boolean {
        return ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL
    }
}

© www.soinside.com 2019 - 2024. All rights reserved.