按住触摸时未检测到边缘触摸

发布于 2025-01-16 05:27:47 字数 2018 浏览 3 评论 0原文

我有一个应用程序,它使用覆盖视图检测屏幕边缘的滑动。现在我想添加一个操作,当覆盖的视图被触摸并保持而不移动时将执行该操作。然而,我观察到一些奇怪的行为,经过几个小时的尝试和搜索,我怀疑这些行为是由 Android 的意外手掌触摸拒绝功能引起的。我的观察:

  • 如果我触摸并按住一段时间然后松开而不移动,则不会检测到任何事件。 (这就是问题所在)
  • 如果我快速触摸并释放,则会连续生成动作向下和向上事件。
  • 上述对于 MotionEvent 和 onClickListener 的行为方式相同。
  • 如果我触摸并按住任意时间,然后移动而不释放,则一旦移动开始,就会生成向下和移动事件。
  • 如果我删除 FLAG_NOT_FOCUSABLE 和 FLAG_NOT_TOUCH_MODAL 标志并在那里写入 0,整个屏幕将变得可触摸并正确检测触摸,除了左/右边缘。
  • 如果我将覆盖层放置在远离屏幕边缘的位置,则一切正常。
  • 在 Android 模拟器上,通过在默认覆盖位置上单击鼠标,一切都可以正常运行。
  • 因此,我通过 OTG 将鼠标连接到我的物理手机,它也可以通过鼠标点击正常工作。
  • 在应用程序的主要设置活动中,在首选项按钮上观察到相同的行为。按住屏幕边缘时没有按钮动画,但如果我快速触摸并释放,则动画和单击会起作用。

我尝试了 WindowManager.LayoutParams 的所有标志,尝试捕获视图的调度事件,但没有成功。

防手掌误触功能有问题吗?有没有办法绕过这个并检测覆盖屏幕边缘的触摸和按住(最好是自定义按住持续时间)?

注意:在 Pixel 2 XL、Android 11 上尝试过。

val overlayedButton = View(this)

val overlayedWidth = 30
val overlayedHeight = resources.displayMetrics.heightPixels / 2

val LAYOUT_FLAG: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
    @Suppress("DEPRECATION")
    WindowManager.LayoutParams.TYPE_PHONE
}

val params = WindowManager.LayoutParams(
    overlayedWidth,
    overlayedHeight,
    LAYOUT_FLAG,
    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
    PixelFormat.TRANSLUCENT
)

params.gravity = Gravity.RIGHT

params.x = 0
params.y = 0

if (overlayedButton!!.parent == null)
{
    wm!!.addView(overlayedButton, params)
}
else
{
    wm!!.updateViewLayout(overlayedButton, params)
}

overlayedButton!!.setOnTouchListener(this)
override fun onTouch(v: View, event: MotionEvent): Boolean {
    when (event.action) {
        MotionEvent.ACTION_DOWN -> {
            //...
    }
        MotionEvent.ACTION_MOVE -> {
            //...
    }
        MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
            //...
    }
    //...
}
    

I have an app which detects swipe on edge of the screen using an overlay view. Now I wanted to add an action which will be performed when the overlayed view is touched and held without moving. However, I observed some weird behaviours, which I suspect, after hours of trying and searching, is caused by the accidental palm touch rejection feature of Android. My observations:

  • If I touch and hold for some duration and then release without moving, no event is detected. (this is the problem)
  • If I quickly touch and release, both action down and up events are generated consecutively.
  • The above behave the same way with both MotionEvent and onClickListener.
  • If I touch and hold as long as I want, and then move without releasing, both down and move events are generated as soon as move starts.
  • If I remove FLAG_NOT_FOCUSABLE and FLAG_NOT_TOUCH_MODAL flags and write 0 there, whole screen becomes touchable and detects the touches correctly, except the left/right edges.
  • If I place the overlay away from the edge towards middle of the screen, everything works correctly.
  • On android emulator, everything works well with mouse clicks on default overlay position.
  • So, I attached a mouse to my physical phone with OTG, it also works correctly with mouse clicks.
  • In the main settings activity of the app, same behaviour is observed on preference buttons. No button animation when pressing and holding on edge of the screen, but animation and click works if I quickly touch and release.

I tried all flags of WindowManager.LayoutParams, tried to capture dispatch events of the view, none worked.

Is the problem palm rejection feature? Is there a way to bypass this and detect touch and hold (preferably with custom hold duration) on edges of the screen on overlay?

Note: Tried on Pixel 2 XL, Android 11.

val overlayedButton = View(this)

val overlayedWidth = 30
val overlayedHeight = resources.displayMetrics.heightPixels / 2

val LAYOUT_FLAG: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
    @Suppress("DEPRECATION")
    WindowManager.LayoutParams.TYPE_PHONE
}

val params = WindowManager.LayoutParams(
    overlayedWidth,
    overlayedHeight,
    LAYOUT_FLAG,
    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
    PixelFormat.TRANSLUCENT
)

params.gravity = Gravity.RIGHT

params.x = 0
params.y = 0

if (overlayedButton!!.parent == null)
{
    wm!!.addView(overlayedButton, params)
}
else
{
    wm!!.updateViewLayout(overlayedButton, params)
}

overlayedButton!!.setOnTouchListener(this)
override fun onTouch(v: View, event: MotionEvent): Boolean {
    when (event.action) {
        MotionEvent.ACTION_DOWN -> {
            //...
    }
        MotionEvent.ACTION_MOVE -> {
            //...
    }
        MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
            //...
    }
    //...
}
    

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

审判长 2025-01-23 05:27:47

也许看看 设置系统手势排除矩形。另外这篇文章解释了操作系统拦截的情况触摸以实现高级手势。

Maybe take a look at setSystemGestureExclusionRects. Also this article explains what is going on with the OS intercepting touches for high-level gestures.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文