Skip to content

Instantly share code, notes, and snippets.

@asadmukhtar28
Last active November 7, 2023 06:08
Show Gist options
  • Save asadmukhtar28/affcf928f9860f44232cc360eaf2ca38 to your computer and use it in GitHub Desktop.
Save asadmukhtar28/affcf928f9860f44232cc360eaf2ca38 to your computer and use it in GitHub Desktop.
ChildrenSwipeHandlingMotionLayout
import android.content.Context
import android.os.SystemClock
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.core.content.PackageManagerCompat.LOG_TAG
import kotlin.math.abs
/**
* Issue: In MotionLayout, swipes over a clickable view doesn't work.
*/
class ChildrenSwipeHandlingMotionLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : MotionLayout(context, attrs, defStyle) {
/*
* we don't want to intercept for viewPager because in viewPager we have recycler that automatic
* handle touches/swipes gracefully with MotionLayout, we are just concerned about clickable views in headers
*/
var viewPagerArea: View? =
null
private var onActionDownYValue = 0f
private var doNotAllowIntercept = false
private fun isInViewPagerArea(event: MotionEvent): Boolean {
return viewPagerArea?.let {
val point = IntArray(2)
it.getLocationOnScreen(point)
val (_, y) = point
if(y == 0) // if viewPager not shown on the screen.
return false
event.y >= y
} ?: true
}
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
return when {
event.actionMasked != MotionEvent.ACTION_DOWN && doNotAllowIntercept -> super.onInterceptTouchEvent(
event
) // when the user swipe from viewPagerArea, just return from here because it automatically handles the motion layout.
else -> when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
onActionDownYValue = event.y
doNotAllowIntercept = isInViewPagerArea(event)
super.onInterceptTouchEvent(event)
}
MotionEvent.ACTION_MOVE -> {
abs(onActionDownYValue - event.y).takeIf { it > 50 }?.run {
onTouchEvent(
MotionEvent.obtain(
SystemClock.uptimeMillis(),
SystemClock.uptimeMillis() + 100,
MotionEvent.ACTION_DOWN,
event.rawX,
event.rawY,
0
)
)
true
} ?: super.onInterceptTouchEvent(event)
}
else ->
super.onInterceptTouchEvent(event)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment