Reputation: 8363
I have two fragments within a SlidingPaneLayout
, fragment A and fragment B. Fragment A is the main fragment and fragment B is the pane that can slide in. On a device which cannot fit both fragment A and fragment B there is a weird behavior. If the user opens fragment B and tries to tap on any views on the left edge of fragment B, the touch gets consumed by SlidingPaneLayout
. This essentially makes the entire left edge of fragment B a deadzone and interferes with certain UI elements such as the up button of a toolbar since it's situated near the left edge. It also interferes with the action buttons of a bottom toolbar. Does anyone know why this happens and how to disable this behavior?
Upvotes: 0
Views: 17
Reputation: 8363
I figured out the cause for this problem or at least I figured out the code causing this to happen. I still don't know why the code that causes this issue is there.
It looks like if the pane is open SlidingPaneLayout
enables edge tracking on a ViewDragHelper
. If the view is LTR, it enables edge tracking on the left. If the view is RTL it enables edge tracking on the right. I have no idea why SlidingPaneLayout
does this but I can see this logic in it's source code.
From looking at SlidingPaneLayout
's source code it doesn't appear that there is an easy way to toggle this behavior. It's essentially hardcoded to always be on.
To workaround the issue I had to extend SlidingPaneLayout
. Then I overrode onInterceptTouchEvent()
and call SlidingPaneLayout
's onInterceptTouchEvent()
. If false is returned, it return false. If true is returned I check to see if a pane is open. If it is, I check if the touch event occurred on the left edge if it's LTR or right edge if it's RTL. If the touch occurred on the edge then I return false. Otherwise I return true.
This effectively prevents SlidingPaneLayout
from eating edge touch events.
Full code for the fixed SlidingPaneLayout
here:
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
}
}
Upvotes: 0