【问题标题】:MotionLayout: How to Limit the 'OnSwipe' event on a specific view instead of 'OnSwipe' on whole screenMotionLayout:如何限制特定视图上的“OnSwipe”事件而不是整个屏幕上的“OnSwipe”
【发布时间】:2019-11-30 09:49:51
【问题描述】:

我有一个带有以下“layoutDescription”(场景文件)的运动布局

    <Transition
    motion:constraintSetStart="@+id/start"
    motion:constraintSetEnd="@+id/end"
    motion:duration="1000">

    <OnSwipe
        motion:touchAnchorId="@+id/button"
        motion:touchAnchorSide="left"
        motion:dragDirection="dragLeft" />

</Transition>
<ConstraintSet android:id="@+id/start">
    <!--    ConstraintSet for starting -->
</ConstraintSet>

<ConstraintSet android:id="@+id/end">
    <!--    ConstraintSet for end -->
</ConstraintSet>

我在这里期望的是,如果用户将“按钮”拖到左侧,那么它应该执行转换,但实际发生的是当用户从屏幕上的任何位置向左拖动(向左滑动)时,这个转换就会被执行!

如何限制动画只在拖动指定视图时起作用?

(我使用“constraintlayout:2.0.0-beta2”)

【问题讨论】:

  • MotionLayout OnSwipe 适用于整个屏幕。如果你想完成这个任务,你可以参考github.com/BALUSANGEM/UberSlideUp
  • 谢谢@SurajGhadge。您的宝贵意见引导我找到解决方案!
  • 欢迎您,能帮到您真是太好了。

标签: android android-animation android-motionlayout


【解决方案1】:

更新答案:使用 ConstraintLayout 2.0.0 alpha-5,您可以简单地使用

app:tou​​chRegionId

在您的“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 文件夹中的 attrs.xml (res/values/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>

【讨论】:

    【解决方案2】:

    其实onSwipe可以使用touchRegionIdtargetIdOnClick

    【讨论】:

    • 哈哈,我的错!其作品。它可从 alpha 5 版本中获得。谢谢
    • 我想知道 OnClickOnSwipe 是否适用于你们的相同视图,还是它是一个错误?
    猜你喜欢
    • 1970-01-01
    • 2020-06-15
    • 1970-01-01
    • 1970-01-01
    • 2019-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多