如何让 onTouchEvent、长按和上下文菜单协同工作?

Posted

技术标签:

【中文标题】如何让 onTouchEvent、长按和上下文菜单协同工作?【英文标题】:How to get onTouchEvent, long click and context menu working together? 【发布时间】:2011-09-04 23:06:54 【问题描述】:

在我们的应用程序中,我们有一个自定义视图(扩展ImageView),我们在其中处理触摸事件以记录数据。我想在这个视图中添加上下文菜单功能,并遵循官方 android 文档中的指南。

onTouchEvent 代码本身可以正常工作。上下文菜单代码也可以正常工作。但是,如果我同时添加它们,上下文菜单代码将停止工作。我发现添加了两段代码后,onCreateContextMenu 永远不会被调用,因此上下文菜单永远不会显示。

根据我对Android文档的解释,从onTouchEvent返回false表示该事件没有被消费,所以应该使用它做进一步处理。出于某种原因,这里没有发生。如果有人能告诉我我错过了什么,我将不胜感激。顺便说一句,目标是运行 2.3.4 ROM 的 Nexus One。

这是自定义视图中onTouchEvent 的代码:

public boolean onTouchEvent(MotionEvent event) 

    switch (event.getAction())
    
        case  MotionEvent.ACTION_DOWN:
            // Add event coordinates to an arraylist
            break;
    

    return false;

提前感谢您的帮助。

【问题讨论】:

能不能也贴一下longclick代码? 您的意思是我根据 Snicolas 的评论尝试的代码?很简单:@Override public boolean onLongClick(View v) openContextMenu(myView); return true; 【参考方案1】:

详细说明 hackbod 答案,您可能应该将return super.onTouchEvent(event); 作为最后一个方法声明。

我猜如果你不处理这个事件,如果你不调用默认的 View 行为,那么没有人会做任何事情,什么都不会发生。

返回值的点可能是例如调用某些祖先的默认行为,并让派生类知道祖先是否处理了事件。

在 Android Developers 上做了一些搜索后,参考主题 override an existing callback method for View here 它说:

这允许您为自定义视图中的每个事件定义默认行为,并确定是否应将事件传递给其他子视图。

因此,返回值背后的主要思想是让 Android 知道是否应该将事件传递给子 View。

HTH

编辑:

关于您在评论中提到的“方向”,一般来说(即不仅在 Android 上)UI 事件处理过程是这样的:

在某些时候,您的派生自定义控件会收到该事件。在您的事件挂钩实现中,是否涉及您的祖先的行为取决于您。这就是关于类继承方向的全部内容。

然后,还有另一个方向,与 UI 控件层次结构相关的方向。您的自定义控件可能包含在一个更大的控件容器中,您的控件也可能包含其他内部控件(文本框、按钮等)。关于这个方向,如果您声明不处理事件(返回 false),那么 UI 事件处理机制会将存储桶传递给 包含 (?) 控件(想想你的后台那个) .

【讨论】:

是的,hackbod 的建议效果很好。我试图了解它是如何工作的。我读了你的链接和Handling UI events subtopic。那里说“[...] 首先调用事件处理程序,然后从类定义中调用适当的默认处理程序”。现在我对 UI 事件的发展方向感到困惑:第一个文档提到子视图,而这个文档说“首先是事件处理程序,其次是默认处理程序”。看来我需要一个很好的教程来解释这种机制是如何工作的。你会碰巧有一个链接吗? 不,对不起,我没有这样的链接。但我编辑了我的答案,并试图澄清我对你提到的方向的想法。 非常感谢您的详细回复,非常感谢。如果您不介意,我还有一个问题:在您的编辑中,您提到调用祖先行为和事件处理机制,将消息传递给包含控件。这一切都说得通。在原始回复中,您引用了 Android 文档 w.r.t 将事件传递给子视图。我现在想要掌握的是其他子视图(谁的孩子,顺便说一句?)如何从我的控制中接收事件。事件是否会传递给父级,然后父级会通知其所有其他子视图有关此事件? 您是否要向上类层次调用默认行为,这取决于您的派生类实现。如果您声明不使用它,则可能接收事件的其他视图是与您的视图相关的视图,具体取决于 UI 层次结构,即 XML 布局中定义的层次结构。在这种情况下,子关系或父关系与类继承无关,而是指容器/包含控制关系。喜欢<LinearLayout><EditText /><Button /><CustomControl /></LinearLayout> 再次感谢您的帮助。我了解类层次结构部分。让我看看我是否使用您的示例正确理解了 UI 层次结构部分:如果我在 CustomControl 中收到一个触摸事件并返回 false 表示我没有使用它,LinearLayout 是否得到它并通知 EditText 和/或Button?作为一个仅供参考,在我的特殊情况下,它是MyImageView extends ImageView,我试图通过ImageView 的实现获得长点击-> 上下文菜单功能,同时通过MyImageView 类跟踪触摸事件。 【参考方案2】:

你可以从你的长按监听器中调用,

openContextMenu(View view)

http://developer.android.com/reference/android/app/Activity.html#openContextMenu(android.view.View)

【讨论】:

是的,但只要有onTouchEvent 代码,就不会调用长按监听器。【参考方案3】:

不要在OnCreate()注册上下文菜单,在onTouch()之前注册 返回真;

registerForContextMenu(View v);
openContextMenu(View v);
return true;

【讨论】:

【参考方案4】:

返回 false 告诉父级您没有使用该事件。 View 的默认实现为该视图实现触摸处理;如果你想让它执行,你必须调用 super.onTouchEvent(event);

【讨论】:

感谢您的回复。你能澄清一下“视图的默认实现为该视图实现触摸处理”吗?你的意思是即使我返回false,父级的触摸处理代码也不会运行?如果是这样,onTouchEvent 中的返回值有什么意义?【参考方案5】:

我最近遇到了类似的问题。当我在RecyeclerView 的孩子中启用长点击时,RecyclerViewonTouchEvent 中无法接收到ACTION_DOWN 事件。

如果我改为RecyclerViewdispatchTouchEvent,我会工作。可以接收ACTION_DOWN 事件。

【讨论】:

以上是关于如何让 onTouchEvent、长按和上下文菜单协同工作?的主要内容,如果未能解决你的问题,请参考以下文章

长按和鲍勃菜单[关闭]

长按和触摸开始

如何在Android中访问菜单按钮onLongClick?

在HAL for STM32中实现单按、长按和双按功能

具有单按和长按事件的 UIButton 快速

UIbutton 长按和 Touch Up 里面