Warm tip: This article is reproduced from serverfault.com, please click

android-MotionLayout可防止在所有视图上使用ClickListener

(android - MotionLayout prevents ClickListener on all Views)

发布于 2020-04-21 13:49:58

我正在将MotionLayout与scene-xml一起使用:

<Transition
    motion:constraintSetStart="@+id/start"
    motion:constraintSetEnd="@+id/end"
    >
    <OnSwipe
        motion:touchAnchorId="@+id/v_top_sheet"
        motion:touchRegionId="@+id/v_top_sheet_touch_region"
        motion:touchAnchorSide="bottom"
        motion:dragDirection="dragDown" />
</Transition>

2个ConstraintSets仅引用2个View ID:v_notifications_containerv_top_sheet

在我的活动中,我想将普通的ClickListener设置为此MotionLayout中的其他视图之一:

iv_notification_status.setOnClickListener { Timber.d("Hello") }

该行已执行,但ClickListener从未触发。我搜索了其他帖子,但是大多数帖子都涉及在与相同的View上设置ClickListener的问题motion:touchAnchorId这里不是这种情况。ClickListener设置为一个在MotionLayout设置中未曾提及的视图。如果删除该app:layoutDescription属性,则单击有效。

我也尝试使用setOnTouchListener,但也从未调用过。

如何在MotionLayout中设置点击侦听器?

Questioner
muetzenflo
Viewed
23
muetzenflo 2020-05-10 19:35:52

借助这篇出色的中篇文章,我发现即使运动场景仅包含一个OnSwipe过渡,MotionLayout仍会拦截单击事件。

因此,我编写了一个自定义的MotionLayout,以仅处理ACTION_MOVE所有其他触摸事件并将其传递到“视图”树中。奇迹般有效:

/**
 * MotionLayout will intercept all touch events and take control over them.
 * That means that View on top of MotionLayout (i.e. children of MotionLayout) will not
 * receive touch events.
 *
 * If the motion scene uses only a onSwipe transition, all click events are intercepted nevertheless.
 * This is why we override onInterceptTouchEvent in this class and only let swipe actions be handled
 * by MotionLayout. All other actions are passed down the View tree so that possible ClickListener can
 * receive the touch/click events.
 */
class ClickableMotionLayout: MotionLayout {

    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    override fun onInterceptTouchEvent(event: MotionEvent?): Boolean {
        if (event?.action == MotionEvent.ACTION_MOVE) {
            return super.onInterceptTouchEvent(event)
        }
        return false
    }

}