Updated answer : with the ConstraintLayout 2.0.0 alpha-5 you can simply use
app:touchRegionId
in your "OnSwipe" for the same behaviour. Also can use 'app:targetId' for "OnClick" usages.
Thanks @RuslanLeshchenko
Original answer :
I managed to do this finally by extending MotionLayout and override onTouchEvent to forward the event to required view.
Create the custom layout by extending MotionLayout
class SingleViewTouchableMotionLayout(context: Context, attributeSet: AttributeSet? = null) : MotionLayout(context, attributeSet) {
private var viewToDetectTouch1 :View? = null
private var viewToDetectTouchRes :Int = -1
private val viewRect = Rect()
private var touchStarted = false
init {
setTransitionListener(object : MotionLayout.TransitionListener {
override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {
}
override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {
}
override fun onTransitionChange(p0: MotionLayout, p1: Int, p2: Int, p3: Float) {
}
override fun onTransitionCompleted(p0: MotionLayout, p1: Int) {
touchStarted = false
}
})
context.theme.obtainStyledAttributes(
attributeSet,
R.styleable.SingleViewTouchableMotionLayout,
0, 0).apply {
try {
viewToDetectTouchRes = getResourceId(
R.styleable.SingleViewTouchableMotionLayout_viewToDetectTouch, 0)
} finally {
recycle()
}
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
viewToDetectTouch1 = (parent as View).findViewById<View>(viewToDetectTouchRes)
}
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.actionMasked) {
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
touchStarted = false
return super.onTouchEvent(event)
}
}
if (!touchStarted) {
viewToDetectTouch1?.getHitRect(viewRect)
touchStarted = viewRect.contains(event.x.toInt(), event.y.toInt())
}
return touchStarted && super.onTouchEvent(event)
}
}
And add the custom attribute which will be used to declare the View that gonna receives the events to trigger the Transition/animation.
Add these styleable to your attrs.xml in your res folder (res/values/attrs.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SingleViewTouchableMotionLayout">
<attr name="viewToDetectTouch" format="reference" />
</declare-styleable>
</resources>
Thats it!!
This way we can archive MotionLayout OnSwipe on a specified view.
Layout XML file now will look like this :
<your_package.SingleViewTouchableMotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/motion_file"
app:viewToDetectTouch="@+id/triggerView"
>
<!-- Notice that 'app:viewToDetectTouch' hold the id of the view we interested -->
<!-- View we interested -->
<View
android:id="@+id/triggerView"
android:layout_width="50dp"
android:layout_height="50dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:background="@color/colorBlack"
/>
</your_package.SingleViewTouchableMotionLayout>