android - 如何在触摸位置附近显示自定义弹出窗口,就像我们使用 ContextMenu 时那样?

标签 android android-recyclerview touch-event android-popupwindow android-contextmenu

背景

看到正式不可能有一个具有自定义 View 甚至行图标的上下文菜单 ( here ),我决定创建我自己的解决方案(具有类似它的自定义 View )。

问题

在 RecyclerView 上使用上下文菜单时,触摸位置很重要,因此如果您长时间触摸某个项目,上下文菜单将尝试出现在触摸位置附近(从 here 中获取的示例),而无需我提供此信息(意思是通过 OnClickListener 或 onLongClickListener ):

enter image description here

但是,我在更基础的类(class)中找不到如何做到这一点。

我尝试过的

可以通过长按来显示 PopupWindow,如下所示:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val inflater = LayoutInflater.from(context)
    val holder = ViewHolder(inflater.inflate(R.layout.list_item_main, parent, false))
    holder.itemView.setOnLongClickListener {
        val contextMenuView=inflater.inflate(R.layout.context_menu,null)
        val popupWindow = PopupWindow(contextMenuView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true)
        popupWindow.showAsDropDown(holder.itemView,0,0);
        true
    }
    return holder
}

而且,如果你想要一个漂亮的背景而不是透明的,你可以使用 ListPopupWindow 的变通方法,如果你不想要一个列表,你可以设置它的 promptView ,这样(代码可用 here ) :

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val inflater = LayoutInflater.from(context)
    val holder = ViewHolder(inflater.inflate(R.layout.list_item_main, parent, false))
    val maxAllowedPopupWidth = context.resources.displayMetrics.widthPixels * 90 / 100
    holder.itemView.setOnLongClickListener {
        val contextMenuView = inflater.inflate(R.layout.context_menu, null)
        val listPopupWindow = ListPopupWindow(context)
        contextMenuView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
        val width = min(maxAllowedPopupWidth, contextMenuView.measuredWidth)
        listPopupWindow.setPromptView(contextMenuView)
        listPopupWindow.setContentWidth(width)
        listPopupWindow.anchorView = it
        listPopupWindow.show()
        true
    }
    return holder
}

我不确定我计算出的最大宽度,因为我找不到弹出窗口的最大尺寸。我知道上下文菜单有一些最大值,然后出于某种原因它只是截断了文本。也许它和 Dialog 一样?除了对话框,我可以找到最大宽度,但我找到了最小宽度:windowMinWidthMajorwindowMinWidthMinor

但回到问题:我在这里找不到任何与将弹出窗口放在触摸位置附近相关的功能。

这就是我得到的,例如:

enter image description here

问题

  1. 如何将弹出窗口设置为出现在屏幕上的触摸位置附近,甚至不处理 onTouch 事件,就像在使用 ContextMenu 的示例中所做的那样?

  2. 上下文菜单(或类似菜单)是否有一些我可以获得的属性,以设置为我显示的最大尺寸(简而言之:默认最大宽度)?如果是这样,我该如何使用它?如何设置宽度和高度以考虑膨胀 View 之一?

最佳答案

我已经有一段时间没有这样做了,但我认为我们遇到了同样的问题。让我看看我能不能回答。

无法为 EditText 制作自定义上下文菜单是我最终决定创建 a library with custom components for Mongolian 的主要原因之一。 .虽然垂直的蒙古语部分对您没有用,但其他自定义弹出窗口的概念应该相同。

这是我所拥有的几个屏幕截图:

这是一个使用自定义弹出菜单的自定义 EditText。它需要用户触摸位置来放置弹出位置。

enter image description here

next one是设置弹出窗口位置的不同方法的更一般的演示。

enter image description here

这两个演示都包含在 mongol-library demo app 中.

我的自定义菜单是 PopupWindow 的子类。你可以找到源代码 here .

我把它放在特定位置的方法是使用 showAtLocation 方法,我记得这只是 PopupWindow 上的一个普通方法:

private void showMongolContextMenu(MongolMenu menu, int xTouchLocation, int yTouchLocation) {
    float paddingPx = CONTEXT_MENU_TOUCH_PADDING_DP * getResources().getDisplayMetrics().density;
    Rect menuSize = menu.getDesiredSize();
    int y = yTouchLocation - menuSize.height() - (int) paddingPx;
    menu.showAtLocation(this, Gravity.NO_GRAVITY, xTouchLocation, y);
}

该代码来自here .

哦,是的,我也在自定义键盘中使用了它:

enter image description here

有关更多信息,请参阅这些类:

关于android - 如何在触摸位置附近显示自定义弹出窗口,就像我们使用 ContextMenu 时那样?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57290574/

相关文章:

android - 增加 SeekBar 的触摸优先级

android - 没有 API < 26 的虚拟方法 MediaRecorder.setOutputFile?

android - 在 RecyclerView 中平均分配项目

Android - 等待触摸事件

java - 在 Recyclerview Adapter (Android) 中操作数据的位置

java - 即使在将适配器设置为布局管理器之后,我也面临着 RecyclerView 没有附加适配器的问题。我一个

android - 矩阵坐标中的点

安卓 Volley : ImageRequest deprecated

android - 在扩展函数中检索返回值的类

java - 我想在另一个 Activity 中将图像传递到我的 ImageView ?