更新答案:使用 ConstraintLayout 2.0.0 alpha-5,您可以简单地使用
应用程序:touchRegionId
在您的“OnSwipe”中进行相同的行为。也可以将 'app:targetId' 用于“OnClick”用途。
谢谢@RuslanLeshchenko
原始答案:
我最终通过扩展 MotionLayout 并覆盖 onTouchEvent 将事件转发到所需的视图来做到这一点。
通过扩展 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)
}
}
并添加将用于声明将接收事件以触发转换/动画的视图的自定义属性。将这些样式添加到您的 res 文件夹 (res/values/attrs.xml) 中的 attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SingleViewTouchableMotionLayout">
<attr name="viewToDetectTouch" format="reference" />
</declare-styleable>
</resources>
而已!!这样我们就可以在指定的视图上归档 MotionLayout OnSwipe。
布局 XML 文件现在将如下所示:
<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>