Android:获取菜单项的视图引用

70

我计划在我的应用程序中使用快速动作UI模式。Android Quick Actions UI Pattern。 快速操作窗口需要一个基准视图以保持粘附。

    quickAction.show(View pivotView);
我打算在菜单项中使用快速操作,我可以访问被点击的项目。 但问题是我需要从菜单项引用一个视图,以便将其传递给快速操作。
如何获取所选menuItem中视图的引用?

你用过这个链接吗?http://www.londatiga.net/it/how-to-create-quickaction-dialog-in-android/ - NikhilReddy
@NikhilreddyGujjula 的链接无法访问。 - Yashwanth Kumar
很久以前我尝试过,它对我起作用了,但是我现在没有代码,抱歉。 - NikhilReddy
7个回答

114
您可以通过在xml中为菜单项提供actionViewClass属性来实现此目的,然后您将能够获得所需的旋转视图。代码类似于以下内容:
<item
    android:id="@+id/menu_find"
    android:showAsAction="ifRoom"
    android:actionViewClass="android.widget.ImageButton"
    />

在你的 OnCreateOptionsMenu 中这样做

public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    getMenuInflater().inflate(R.menu.menu_search, menu);
    locButton = (ImageButton) menu.findItem(R.id.menu_find).getActionView();
    locButton.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            createPopup();
            mQuickAction.show(v);
        }
    });
    return true;
}

非常感谢!我遇到了一个奇怪的问题,在 Android 4.1 上,取景器会在操作栏中找到一个旋转器,但在 4.2 上它只返回 null,这个修复了它。 - Igor Čordaš
setOnMenuItemClickListener对我很有帮助,如果您想直接操作菜单项。 - AnkitRox
21
如果你使用最新的库,请使用app:actionViewClass。 (res-auto) - EngineSense

46

这是一个老问题,但我最近遇到了 actionViewClass 属性的一些问题。对于以后也会遇到此类问题的人...

onOptionsItemSelected 中调用 findViewById(R.id.mnu_item) 会返回一个 View 锚点。

MenuItems 上的 QuickActions 不是很好的设计,但是我发现它们是实现带有自定义背景的子菜单的最简单方法。


我猜你需要在获取'menuItem' 'view'锚点之前至少点击一次'menuItem'。 - Leebeedev
没错,findViewById() 方法调用必须在运行时执行。 - loadedion
感谢@ASH的回答,如果我们放置actionViewClass,它会失败。这个方法非常有效。 - abhy

27
为了获得菜单项的参考视图,我们需要这样做。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.section, menu);

    new Handler().post(new Runnable() {
        @Override
        public void run() {

            final View menuItemView = findViewById(R.id.action_preview);
            // SOME OF YOUR TASK AFTER GETTING VIEW REFERENCE

        }
    });


    return true;
}

2
最好的方法是不创建任何自定义视图并设置ActionView。 - user25
1
真的很丑(感谢API),但这确实是一个可行的解决方案,非常感谢。 - brucemax
1
在 API 28 中无法工作。 - Kishy Nivas
你太棒了,这对我有用。非常感谢你的分享! - Tomas M

6

对于任何想要查找菜单视图项的人(比如我),以下是一些更新。

如果您可以访问并使用AppCompat的工具栏,则有一种方法。这不是最有效的方法,但这是我发现的最简单的访问菜单项视图的方法。

public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);

    // Find Menu
    for (int toolbarChildIndex = 0; toolbarChildIndex < toolbar.getChildCount(); toolbarChildIndex++) {
        View view = toolbar.getChildAt(toolbarChildIndex);

        // Found Menu
        if (view instanceof ActionMenuView) {
            ActionMenuView menuView = (ActionMenuView) view;

            // All menu items
            for (int menuChildIndex = 0; menuChildIndex < menuView.getChildCount(); menuChildIndex++) {
                ActionMenuItemView itemView = (ActionMenuItemView) menuView.getChildAt(menuChildIndex);
                // Do something to itemView...
            }
        }
    }
}

1

通用代码,也适用于Android 10

/**
* pass toolbar and menu item id, i.e. R.id.menu_refresh
*/
@Nullable
@Throws(
    IllegalAccessException::class,
    NoSuchFieldException::class
)
fun getMenuItemView(toolbar: Toolbar?, @IdRes menuItemId: Int): View? {
    val mMenuView: Field = Toolbar::class.java.getDeclaredField("mMenuView")
    mMenuView.setAccessible(true)
    val menuView: Any? = mMenuView.get(toolbar)
    (menuView as ViewGroup).children.forEach {
        if(it.id == menuItemId) {
            return it
        }
    }
    return null
}

很快 getDeclaredField 将被屏蔽,必须添加此 @SuppressLint("SoonBlockedPrivateApi")。 - JPM

-2

Kotlin!!

override fun onCreateOptionsMenu(Menu menu): Boolean {

  /*Adding menu items to action bar*/
  menuInflater.inflate(R.menu.main, menu)

  /*Getting menu item*/
  val locButton: MenuItem = menu.findItem(R.id.menu_find)

  /*Creating click listener*/
  locButton.setOnMenuItemClickListener{
    /*TODO: Handle it*/
    true
  }

  return true;
}

-2
在主活动类中,最好重写onOptionsItemSelected(...)方法;应该如下所示:
public boolean onOptionsItemSelected(MenuItem item) {
  // the id is of type int
  int someId = item.getItemId();
  // can use an if() or switch() statement to check if id is selected
  //a Toast message can be used to show item is selected
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接