gpt4 book ai didi

android - child 拦截触摸事件的MotionLayout问题

转载 作者:行者123 更新时间:2023-12-02 11:20:31 41 4
gpt4 key购买 nike

我的主布局中有一个用于根容器的motionLayout。在里面,还有其他的景色。其中之一是 frameLayout,包含一个 fragment 。该 fragment 是一个页面,由一个 NestedScrollView 等组成...
MotionLayout 具有仅用于水平滑动的 OnSwipe,而 NestedScrollView 应该只能垂直滚动。我不得不扩展 MotionLayout onInterceptTouchEvent 方法(查看下面的代码),并且只将那些非水平触摸事件传递给 children 。到目前为止非常简单,它有效 .

问题是,当我 开始 在吸收某种触摸事件(如按钮或 NestedScrollView)的 View 上滑动它会弄乱 motionLayout 转换并立即跳过帧,因此 anchor 与我的鼠标位置相对应。过渡几乎完全在一个帧中进行,并扼杀了 UI 体验。我的猜测是,如果 motionLayout 将 X1 和 X2 用于转换,则 X1 值是导致问题的值,其值来自不应该出现的位置。但是当然,当我开始在触摸吸收元素上滑动时。

这是我的 customMotionLayout 的 OnInterceptTouchEvent 的覆盖方法:

 override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
super.onInterceptTouchEvent(event)

return when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
previousX = event.x.toInt()
previousY = event.y.toInt()
mIsScrolling = false
false
}
MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> {
mIsScrolling = false
false
}
MotionEvent.ACTION_MOVE -> {
if (mIsScrolling) true
else {
var xMotion: Int = abs(previousX - event.x.toInt())
var yMotion: Int = abs(previousY - event.y.toInt())
previousX = event.x.toInt()
previousY = event.y.toInt()
if (xMotion >= yMotion) {
mIsScrolling = true
true
} else false}}
else -> {
mIsScrolling = false
false
}
}
}

这是相关的过渡:
    <Transition android:id="@+id/options_to_now" motion:motionInterpolator="easeInOut"
motion:pathMotionArc="none"
motion:constraintSetStart ="@id/options_state"
motion:constraintSetEnd="@id/now_state"
motion:duration="100">
<OnSwipe
motion:maxAcceleration="100"
motion:maxVelocity="100"
motion:dragDirection="dragRight"
motion:touchAnchorId="@id/view_options"
motion:touchAnchorSide="left"
motion:touchRegionId="@id/view_options"/>
</Transition>

我通过测试确保 MotionDescripton 和布局没有问题。

值得注意的是,当我不触摸吸收某种触摸事件的元素时,运动效果很好。就像我的布局中的空格一样,它只会在我滑过这些元素时引起提到的问题。

也许如果我知道 motionLayout 过渡如何与 touchPositions 相关,我可以解决它。

更新 1:我注意到如果我点击一个空白区域(简单的点击 ACTION_DOWN),然后滑动,即使从那些顽皮的元素开始,问题也会有所不同。该点击以某种方式更新了过渡的协调位置。它以我单击的位置为起点,例如 x1。然后,当我滑过吸收触摸事件的东西时,它会从那里获得 x2。现在我在确切的下一帧中看到的结果就像我将运动从 x1 滑动到 x2 一样。

更新 2:我注意到的另一件事我认为与我的问题非常相关,当我完成滑动时,转换始终处于 STARTED 状态。就像我从 x1 滑动到 x2 一样,它的状态从开始、完成然后开始。所以我想当我的下一次滑动出现时,它认为我的手指一直在触摸,我手动滑动,而我没有。当我在屏幕上没有手指的情况下完成滑动 geture 并完成它的完整循环时,在监听转换和打印状态后,日志中的结果如下。所以最后一个被调用的事件开始了,这对我来说是不合逻辑的。
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.014359029
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.02863888
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.044761233
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.06311959
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.09285617
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.12685902
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.17269236
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.22314182
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.27269235
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.32545927
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.389359
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.4449254
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.44595188
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.4948284
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.57895637
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.6884479
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.814522
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.8918733
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.95612586
D/e: Changed, state = -1 / p1 = 2131230901 / p2 = 2131230907 / p3 = 0.9949746
D/e: Completed: state = 2131230907 / p1 = 2131230907
D/e: Started, state = 2131230907 / p1 = 2131230901 / p2 = 2131230907
Changed, state = 2131230907 / p1 = 2131230901 / p2 = 2131230907 / p3 = 1.0

更新 3:我注意到的另一件事是,当且仅当转换成功更改运动状态时,我们会遇到一种情况,即通过单击这些触摸吸收元素之一,motionLayout 不会收到 OnTouchEvent! (这就是我正在处理的问题行为存在的情况)并且如果我在应用程序启动时没有刷任何东西(虽然没有问题 ),通过单击按钮,我在motionLayout 中收到ACTION_DOWN 和ACTINO_UP。因此,无论在转换到新状态后motionLayout 中发生什么,它都会阻止motionLayout 从子项接收OnTouchEvents。

更新 4:我对 MotionLayout 如何处理场景创建不是很熟悉,但如果有人知道,是否可能是motionLayout 动态创建了一个场景,以某种方式阻止 onTouchEvent 一直传回父级?

更新5:所以当motionLayout没有收到带有ACTION_DOWN的motionEvent时,就会出现问题。我查看了调用堆栈并认为它应该与 View 吸收事件 dispatchTouchEvent 方法有关,当开始在触摸吸收元素上滑动时为 ACTION_DOWN 返回 true,在其他情况下返回 false。因此,在 dispatchTouchEvent 中返回 true 会导致 motionLayout 没有收到 ACTION_DOWN 并导致问题。在 dispatchTouchEvent 内部,区分两种情况的结果的代码是部分:
  if (onFilterTouchEventForSecurity(event)) {
...
if (!result && onTouchEvent(event)) {
result = true;
}
}

例如,单击按钮时 OnTouchEvent(event) 返回 true,单击空格时返回 false。

我正在使用 2.0.0-beta4 版本的约束布局。

最佳答案

我想我发现了问题,它是motionLayout的onInterceptTouchEvent中的mRegionView。在该方法的某个地方,它使用 mRegoinView 的左右、顶部和底部检查事件 x 和 y 的边界。我查看了这些值,发现在那些有问题的情况下,这些值有点奇怪,因此该函数返回 false 并且从不调用 motionLayout 的 onTouch 事件。值是:

好情况
× 354
y 450
前 0
左 16
底部 1280
第 752 章

糟糕的情况(如问题中所述,当 1 次转换已成功将状态更改为新状态时,我们开始拖动触摸吸收元素)

× 300
y 450
前 0
还剩 750
底部 1280
对 768

正如你所看到的,左边有 750,这对我来说有点奇怪,我不知道原因。我可能会检查为什么它具有该值并更新此答案,但现在我只是删除了motionLayout 的 onInterceptTouchEvent 中的 boundCheck,因为至少现在我并没有真正使用特定区域。

更新:它是 touchRegion 和 regionId。对于相同的场景和元素(比如按钮),当你第一次点击它时,[在 touchProcess] 它工作正常,但是如果你做一个过渡,那么它在 touchProcess 中返回一个错误的 View ,regionId 返回另一个 View ,它是前一个过渡场景的父级。我不知道为什么会发生这种情况,或者是某种错误(考虑到这个库仍然是测试版,可以理解)。
所以我只是覆盖了 MotionLayout 的 touchProcess 并忽略了检查 TouchRegion 边界的部分。

关于android - child 拦截触摸事件的MotionLayout问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59504422/

41 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com