You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android溢出菜单子菜单项添加OnLongClickListener失效问题求助

解决Android溢出菜单子菜单项长按事件不触发的问题

Hey there! I totally get how frustrating it is when a feature you’ve been working on just won’t fire—let’s break down why your long click listeners aren’t working for those submenu items, and fix it.

Why Your Current Code Isn’t Working

The core issue here is that when you set app:actionViewClass on your submenu items, the Android system doesn’t actually use that view when rendering the overflow submenu. For pop-up style submenus (like the one triggered by your "Help" item), Android uses its own default layout and views to display the options. That means the actionView you’re trying to bind the long click to never actually gets shown—so your listener is attached to a view that’s never on screen.

The most reliable way to add long click support is to replace the system’s built-in submenu with a custom PopupMenu. This lets you fully control the menu’s behavior and easily attach both click and long click listeners.

Step 1: Move Submenu to Separate XML

Create a new menu file res/menu/submenu_help.xml with your submenu items:

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/event1" android:title="Event 1" />
    <item android:id="@+id/event2" android:title="Event 2" />
    <item android:id="@+id/event3" android:title="Event 3" />
</menu>

Step 2: Handle Parent Menu Click & Attach Listeners

In your Activity’s onOptionsItemSelected method, trigger the custom PopupMenu when the "Help" item is clicked, then attach both click and long click listeners:

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.help -> {
            // Create PopupMenu anchored to the help menu item
            val popupMenu = PopupMenu(this, findViewById(R.id.help))
            popupMenu.menuInflater.inflate(R.menu.submenu_help, popupMenu.menu)

            // Attach long click listener once the menu is shown
            popupMenu.setOnShowListener {
                // Access the underlying ListView of the PopupMenu
                val popupField = PopupMenu::class.java.getDeclaredField("mPopup")
                popupField.isAccessible = true
                val menuPopupHelper = popupField.get(popupMenu)
                val getListViewMethod = menuPopupHelper.javaClass.getDeclaredMethod("getListView")
                getListViewMethod.isAccessible = true
                val listView = getListViewMethod.invoke(menuPopupHelper) as ListView

                // Set long click listener
                listView.onItemLongClickListener = AdapterView.OnItemLongClickListener { _, _, position, _ ->
                    val selectedItem = popupMenu.menu.getItem(position)
                    when (selectedItem.itemId) {
                        R.id.event1 -> Log.d("Long Click", "Event 1 was long pressed!")
                        R.id.event2 -> Log.d("Long Click", "Event 2 was long pressed!")
                        R.id.event3 -> Log.d("Long Click", "Event 3 was long pressed!")
                    }
                    true
                }
            }

            // Handle regular click events
            popupMenu.setOnMenuItemClickListener { menuItem ->
                when (menuItem.itemId) {
                    R.id.event1 -> {
                        Log.d("Click", "Event 1 clicked")
                        true
                    }
                    R.id.event2 -> {
                        Log.d("Click", "Event 2 clicked")
                        true
                    }
                    R.id.event3 -> {
                        Log.d("Click", "Event 3 clicked")
                        true
                    }
                    else -> false
                }
            }

            popupMenu.show()
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

Solution 2: Target the System’s Submenu ListView (Less Reliable)

If you want to stick with the system’s built-in submenu, you can find the underlying ListView that renders the submenu items and attach a long click listener to it. Note that this relies on internal Android views, so it might break across different versions or OEM skins.

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.help -> {
            // Wait a short time for the submenu to render
            Handler(Looper.getMainLooper()).postDelayed({
                findOverflowSubmenuListView()?.let { listView ->
                    listView.onItemLongClickListener = AdapterView.OnItemLongClickListener { parent, _, position, _ ->
                        val subMenuItem = parent.adapter.getItem(position) as MenuItem
                        when (subMenuItem.itemId) {
                            R.id.event1 -> Log.d("Long Click", "Event 1 long pressed")
                            R.id.event2 -> Log.d("Long Click", "Event 2 long pressed")
                            R.id.event3 -> Log.d("Long Click", "Event 3 long pressed")
                        }
                        true
                    }
                }
            }, 100)
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

// Helper to find the submenu's ListView by traversing the decor view
private fun findOverflowSubmenuListView(): ListView? {
    val decorView = window.decorView as ViewGroup
    val popupViews = mutableListOf<View>()
    traverseViewsForPopups(decorView, popupViews)
    
    return popupViews.firstOrNull { it is ListView && (it as ListView).adapter.count == 3 } as? ListView
}

private fun traverseViewsForPopups(parent: ViewGroup, popupViews: MutableList<View>) {
    for (i in 0 until parent.childCount) {
        val child = parent.getChildAt(i)
        val className = child.javaClass.simpleName
        if (className.contains("PopupWindow") || className.contains("MenuPopup")) {
            if (child is ViewGroup) {
                traverseViewsForPopups(child, popupViews)
                child.children.forEach { subChild ->
                    if (subChild is ListView) popupViews.add(subChild)
                }
            }
        } else if (child is ViewGroup) {
            traverseViewsForPopups(child, popupViews)
        }
    }
}

Final Notes

  • Solution 1 (Custom PopupMenu) is the better choice for long-term compatibility and flexibility—it doesn’t depend on Android’s internal view structures, which can change between versions.
  • Make sure to remove the app:actionViewClass attributes from your original menu XML since they’re not being used anymore.

内容的提问来源于stack exchange,提问作者Gino

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 22:27:44