如何编程判断图标显示在ActionBar还是Overflow Menu中?
嘿,这个需求我之前也遇到过,要判断MenuItem到底是显示在ActionBar上还是藏在溢出菜单里,确实没有直接的公开API,但可以通过一些技巧实现,下面给你两种靠谱的方案:
方案一:通过反射获取内部View并判断位置
Android的Menu和MenuItem内部有未公开的API可以获取到对应的View,我们可以用反射来拿到这个View,然后判断它是否属于ActionBar的容器(比如ActionMenuView或Toolbar)。
实现步骤:
- 在
onPrepareOptionsMenu方法中处理(这个方法会在菜单准备好时调用,包括屏幕旋转、空间变化的场景,适合动态判断) - 反射获取MenuItem对应的View
- 判断View的父容器是否属于ActionBar,进而设置不同色调
@Override public boolean onPrepareOptionsMenu(Menu menu) { // 获取目标MenuItem MenuItem complexSectionItem = menu.findItem(R.id.new_complex_section); View actionView = getMenuItemView(complexSectionItem); if (actionView != null) { boolean isInActionBar = isViewInActionBar(actionView); // 设置图标色调,记得调用mutate()避免Drawable复用导致的全局变色 Drawable icon = complexSectionItem.getIcon().mutate(); int tintColor = isInActionBar ? ContextCompat.getColor(this, R.color.action_bar_icon_tint) : ContextCompat.getColor(this, R.color.overflow_icon_tint); icon.setTint(tintColor); complexSectionItem.setIcon(icon); } // 处理子菜单的Item(子菜单默认在下拉面板里,直接设置溢出色调即可) SubMenu subMenu = complexSectionItem.getSubMenu(); if (subMenu != null) { setSubMenuIconTint(subMenu.findItem(R.id.new_design_i_section)); setSubMenuIconTint(subMenu.findItem(R.id.new_design_t_section)); } return super.onPrepareOptionsMenu(menu); } // 反射获取MenuItem对应的View private View getMenuItemView(MenuItem item) { View actionView = item.getActionView(); if (actionView != null) return actionView; try { // 获取MenuBuilder实例 Method getMenuBuilderMethod = Menu.class.getDeclaredMethod("getMenuBuilder"); getMenuBuilderMethod.setAccessible(true); Object menuBuilder = getMenuBuilderMethod.invoke(item.getMenu()); // 获取MenuItem对应的View Method getItemViewMethod = menuBuilder.getClass().getDeclaredMethod("getItemView", MenuItem.class); getItemViewMethod.setAccessible(true); return (View) getItemViewMethod.invoke(menuBuilder, item); } catch (Exception e) { e.printStackTrace(); return null; } } // 判断View是否属于ActionBar容器 private boolean isViewInActionBar(View view) { ViewParent parent = view.getParent(); while (parent != null) { if (parent instanceof ActionMenuView || parent instanceof Toolbar) { return true; } parent = parent.getParent(); } return false; } // 设置子菜单图标的色调 private void setSubMenuIconTint(MenuItem item) { Drawable icon = item.getIcon().mutate(); icon.setTint(ContextCompat.getColor(this, R.color.submenu_icon_tint)); item.setIcon(icon); }
方案二:通过Toolbar直接查找子View(仅适用于自定义Toolbar)
如果你的项目使用了自定义的Toolbar(而非系统默认的ActionBar),可以直接遍历Toolbar的子View,找到ActionMenuView后,检查目标MenuItem对应的View是否在其中。
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.your_menu_file, menu); // 延迟执行,确保菜单布局完成 new Handler(Looper.getMainLooper()).post(() -> { Toolbar toolbar = findViewById(R.id.your_toolbar_id); ActionMenuView actionMenuView = findActionMenuViewInToolbar(toolbar); if (actionMenuView != null) { View targetItemView = actionMenuView.findViewById(R.id.new_complex_section); MenuItem complexSectionItem = menu.findItem(R.id.new_complex_section); boolean isInActionBar = targetItemView != null && targetItemView.isShown(); // 设置色调逻辑和方案一一致 Drawable icon = complexSectionItem.getIcon().mutate(); int tintColor = isInActionBar ? ContextCompat.getColor(this, R.color.action_bar_icon_tint) : ContextCompat.getColor(this, R.color.overflow_icon_tint); icon.setTint(tintColor); complexSectionItem.setIcon(icon); } }); return true; } // 从Toolbar中找到ActionMenuView private ActionMenuView findActionMenuViewInToolbar(Toolbar toolbar) { for (int i = 0; i < toolbar.getChildCount(); i++) { View child = toolbar.getChildAt(i); if (child instanceof ActionMenuView) { return (ActionMenuView) child; } } return null; }
注意事项:
- 调用
Drawable.mutate()非常重要!如果不调用,修改色调会影响所有使用该Drawable的地方(因为Drawable默认是共享的)。 - 反射方案需要做好异常处理,因为Android不同版本的内部API可能有细微变化。
- 子菜单的Item始终会在下拉面板中显示,不需要额外判断,直接设置对应的色调即可。
内容的提问来源于stack exchange,提问作者DonelSoft
相关产品推荐
相关产品推荐

