感谢@JaredRummler,我找到了一种确定图标是否在溢出菜单中的方法。我在这里发布了完整的代码,收集了他答案中的元素。我还添加了一个帮助方法来获取正确的颜色以调节图标。以下是我当前使用的内容:
ThemeUtils
public final class ThemeUtils {
public static int[] getColors(Context context, int... colorAttrs) {
TypedArray ta = context.getTheme().obtainStyledAttributes(colorAttrs);
int[] colors = new int[colorAttrs.length];
for (int i = 0; i < colorAttrs.length; i++) {
colors[i] = ta.getColor(i, 0);
}
ta.recycle();
return colors;
}
public static int[] getToolbarColors(Context context) {
TypedArray ta = context.getTheme().obtainStyledAttributes(
new int[]{R.attr.toolbarTheme, R.attr.toolbarPopupTheme});
Context overlayTheme = new ContextThemeWrapper(context, ta.getResourceId(0, 0));
Context popupTheme = new ContextThemeWrapper(context, ta.getResourceId(1, 0));
ta.recycle();
int colorNormal = ThemeUtils.getColors(overlayTheme, android.R.attr.textColorPrimary)[0];
int colorInMenu = ThemeUtils.getColors(popupTheme, android.R.attr.textColorSecondary)[0];
return new int[]{colorNormal, colorInMenu};
}
private static void changeIconsColor(View toolbar, Menu menu, int colorNormal, int colorInMenu, boolean isInSubMenu) {
toolbar.post(() -> {
for (int i = 0; i < menu.size(); i++) {
MenuItem item = menu.getItem(i);
changeMenuIconColor(item, colorNormal, colorInMenu, isInSubMenu);
if (item.hasSubMenu()) {
changeIconsColor(toolbar, item.getSubMenu(), colorNormal, colorInMenu, true);
}
}
});
}
public static void changeIconsColor(View toolbar, Menu menu, int colorNormal, int colorInMenu) {
changeIconsColor(toolbar, menu, colorNormal, colorInMenu, false);
}
@SuppressLint("RestrictedApi")
public static void changeMenuIconColor(MenuItem item, int colorNormal, int colorInMenu, boolean isInSubMenu) {
if (item.getIcon() != null) {
Drawable icon = item.getIcon().mutate();
int color = (((MenuItemImpl) item).isActionButton() && !isInSubMenu ? colorNormal : colorInMenu);
icon.setColorFilter(color, PorterDuff.Mode.SRC_IN);
icon.setAlpha(item.isEnabled() ? 255 : 128);
item.setIcon(icon);
}
}
}
ActivityUtils
public final class ActivityUtils {
public static void forceShowMenuIcons(Menu menu) {
if (menu instanceof MenuBuilder) {
MenuBuilder m = (MenuBuilder) menu;
m.setOptionalIconsVisible(true);
}
}
public static ViewGroup findActionBar(Activity activity) {
int id = activity.getResources().getIdentifier("action_bar", "id", "android");
ViewGroup actionBar = null;
if (id != 0) {
actionBar = activity.findViewById(id);
}
if (actionBar == null) {
return findToolbar((ViewGroup) activity.findViewById(android.R.id.content).getRootView());
}
return actionBar;
}
private static ViewGroup findToolbar(ViewGroup viewGroup) {
ViewGroup toolbar = null;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
View view = viewGroup.getChildAt(i);
if (view.getClass() == android.support.v7.widget.Toolbar.class ||
view.getClass() == android.widget.Toolbar.class) {
toolbar = (ViewGroup) view;
} else if (view instanceof ViewGroup) {
toolbar = findToolbar((ViewGroup) view);
}
if (toolbar != null) {
break;
}
}
return toolbar;
}
}
我还在
attrs.xml
中定义了两个属性:
toolbarTheme
和
toolbarPopupTheme
,并在XML中设置了我的工具栏布局。它们的值在
themes.xml
中定义。这些属性由
ThemeUtils.getToolbarColors(Context)
使用,以获取用于着色图标的颜色,因为工具栏通常使用主题覆盖。通过这样做,我只需更改这2个属性的值,就可以更改每个工具栏的主题。
最后,在活动的
onCreateOptionsMenu(Menu menu)
中调用以下内容即可:
ActivityUtils.forceShowMenuIcons(menu)
View toolbar = ActivityUtils.findActionBar(this)
int[] toolbarColors = ThemeUtils.getToolbarColors(this)
ThemeUtils.changeIconsColor(toolbar, menu, toolbarColors[0], toolbarColors[1])
在片段中,可以通过将this
替换为getActivity()
来完成相同的操作。
当更新菜单项图标时,可以调用另一个方法ThemeUtils.changeMenuIconColor()
。在这种情况下,可以在onCreate
中获取工具栏颜色并全局存储以便重复使用。
onCreateOptionsMenu
中使用它时,它会像溢出项一样对ifRoom
项进行染色。但是,当我在onPrepareOptionsMenu
中使用它时,它可以正确地着色,但只有在我打开溢出菜单后才会显示。 (每次我打开溢出菜单时都会调用onPrepare
)。 我尝试从那里调用invalidateOptionsMenu()
,但没有成功。 有什么想法吗? - NicolasonCreate
和onPrepare
两个方法中都试过了。 - NicolasisActionButton
,它应该可以工作。 - Jared Rummler