Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
a simplified code example for how Discord's Android app supports custom panel gesture detection
class OverlappingPanelsLayout : FrameLayout {
private var scrollingSlopPx: Float = 0f
private var velocityTracker: VelocityTracker? = null
private var isScrollingHorizontally = false
private var xFromInterceptActionDown: Float = 0f
private var yFromInterceptActionDown: Float = 0f
... // initialize scrollingSlopPx and VelocityTracker
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
return when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
isScrollingHorizontally = false
xFromInterceptActionDown = event.x
yFromInterceptActionDown = event.y
if (velocityTracker == null) {
velocityTracker = VelocityTracker.obtain()
velocityTracker?.addMovement(event)
} else {
velocityTracker?.clear()
}
false
}
MotionEvent.ACTION_MOVE -> {
if (isScrollingHorizontally) {
true
} else {
// If the horizontal distance in the MotionEvent is more
// than the scroll slop, and if the horizontal distance
// is greater than the vertical distance, start the
// horizontal scroll for the panels.
val xDiff = calculateDistanceX(
startX = xFromInterceptActionDown,
event = event
)
val yDiff = calculateDistanceY(
startY = yFromInterceptActionDown,
event = event
)
if (abs(xDiff) > scrollingSlopPx &&
abs(xDiff) > abs(yDiff)
) {
isScrollingHorizontally = true
true
} else {
false
}
}
}
MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> {
velocityTracker?.recycle()
velocityTracker = null
isScrollingHorizontally
}
else -> false
}
}
override fun onTouchEvent(event: MotionEvent): Boolean {
return when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> true
MotionEvent.ACTION_MOVE -> {
velocityTracker?.addMovement(event)
translateCenterPanel(event)
true
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
velocityTracker?.addMovement(event)
snapOpenOrClose(event)
isScrollingHorizontally = false
true
}
else -> false
}
}
private fun translateCenterPanel(event: MotionEvent) {
// This line maps the x position from the MotionEvent to the
// targeted x position for the center panel.
val targetedX = event.rawX + centerPanelDiffX
// This line makes sure the center panel stays within bounds
// such as the min and max x positions.
val normalizedX = getNormalizedX(targetedX)
updateCenterPanelX(normalizedX)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment