【发布时间】:2012-03-27 10:20:57
【问题描述】:
对于 on Blackberry 的相同功能有一个问题,还有几个不同的线程引用了这个 bug(据我所知,它已经关闭,没有解决方案),但我还没有找到一个专门用于安卓。
我基于某些状态在某些 MenuItems 上调用 setEnabled(false),但它们在视觉上看起来相同。我希望它们以某种方式被抵消,以便用户知道该选项当前不可用 - 有什么方法可以做到这一点?
【问题讨论】:
对于 on Blackberry 的相同功能有一个问题,还有几个不同的线程引用了这个 bug(据我所知,它已经关闭,没有解决方案),但我还没有找到一个专门用于安卓。
我基于某些状态在某些 MenuItems 上调用 setEnabled(false),但它们在视觉上看起来相同。我希望它们以某种方式被抵消,以便用户知道该选项当前不可用 - 有什么方法可以做到这一点?
【问题讨论】:
在所有 android 版本上,最简单的方法是使用此功能将菜单操作图标显示为禁用并使其功能也禁用:
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem item = menu.findItem(R.id.menu_my_item);
if (myItemShouldBeEnabled) {
item.setEnabled(true);
item.getIcon().setAlpha(255);
} else {
// disabled
item.setEnabled(false);
item.getIcon().setAlpha(130);
}
}
【讨论】:
我遇到了同样的问题。有两种方法可以让它工作:
我现在用的。在onPrepareOptionsMenu() 中自己更改图标:
public boolean onPrepareOptionsMenu(Menu menu) {
boolean menusEnabled = reachedEndOfSlidehow(); // enable or disable?
MenuItem item = menu.findItem(R.id.menu_next_slide);
Drawable resIcon = getResources().getDrawable(R.drawable.ic_next_slide);
if (!menusEnabled)
resIcon.mutate().setColorFilter(Color.GRAY, PorterDuff.Mode.SRC_IN);
item.setEnabled(menusEnabled); // any text will be automatically disabled
item.setIcon(resIcon);
}
您可以致电invalidateOptionsMenu()(或来自ABS,supportInvalidateOptionsMenu())来重建菜单。
编辑:更新的解决方案 2
来源:https://groups.google.com/forum/?fromgroups#!topic/actionbarsherlock/Z8Ic8djq-3o
【讨论】:
我找到了一种使用可绘制选择器 xml 文件解决此问题的新方法。您只需使用要在菜单项中使用的图标创建一个选择器,然后您可以更改位图的色调、alpha 或两者:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true">
<bitmap android:src="@drawable/ic_menu_item"
android:tint="@color/enabled_color"
android:alpha="@integer/enabled_alpha"/>
</item>
<item android:state_enabled="false">
<bitmap android:src="@drawable/ic_menu_item"
android:tint="@color/disabled_color"
android:alpha="@integer/disabled_alpha"/>
</item>
</selector>
作为旁注;我喜欢将色调设置为"?android:attr/textColorPrimary" 用于启用状态,"?android:attr/textColorHint" 用于禁用状态。这样它会根据使用的主题进行调整。
然后您可以将菜单 xml 文件中的图标设置为选择器资源:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/menu_action"
android:orderInCategory="0"
android:title="@string/title_menu_action"
android:icon="@drawable/ic_menu_item_selector"
app:showAsAction="ifRoom"/>
</menu>
然后当您调用item.setEnabled(enabled) 时,图标的颜色和/或 alpha 会随着状态而改变!
【讨论】:
我的做法是在 NavigationView 中使用“itemIconTint”,您也可以使用“itemTextColor”将文本变灰
这是导航视图:
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:itemBackground="@color/white"
android:background="@color/white"
app:itemTextColor="@color/menu_text_color"
app:itemIconTint="@color/menu_text_color"
app:menu="@menu/main_drawer" />
而“@color/menu_text_color”是一个选择器:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="@color/primaryColor" />
<item android:state_enabled="false" android:color="@color/disabled_text_color" />
<item android:color="@color/primaryText" />
</selector>
最后,如果你想禁用一个菜单项,
MenuItem item = mNavigationView.getMenu().findItem(R.id.your_menu_item);
item.setEnabled(isEnable);
完成!
【讨论】:
我遇到了一个问题,即我的文本和图标都没有明显变化。其他答案要么对我不起作用,要么不是很优雅。这是适用于最新Material recommendations 的答案。
您应该可以简单地在onPrepareOptionsMenu(menu: Menu) 中调用menu.findItem(R.id.menu_my_item).isEnabled = false。
(如果您需要onPrepareOptionsMenu 再次运行,您只需调用invalidateOptionsMenu() 或activity?.invalidateOptionsMenu()(来自片段),应用程序将排队重新创建菜单。或者您可以存储菜单项在成员变量中稍后对其进行修改,但请注意在 onDestroyOptionsMenu 中销毁对它的引用以避免内存泄漏。)
菜单项被禁用的事实应该足以自动使文本或图标变灰。困难在于设置你的样式来完成这项工作。
首先创建一个您希望图标和文本使用的颜色状态列表my_color_state_list.xml(例如,启用时为黑色,禁用时为灰色)。 (有关示例,请参阅完整答案。)
如果您使用com.google.android.material.appbar.MaterialToolbar,您可以通过提供自定义主题覆盖来告诉它使用此选择器来显示图标和文本。在您的活动的 XML 中,为工具栏提供属性 android:theme="@style/Foo" 并将该样式定义为:
<style name="Foo">
<item name="colorControlNormal">@color/my_color_state_list</item>
<item name="actionMenuTextColor">@color/my_color_state_list</item>
</style>
现在当通过menu.findItem(R.id.menu_my_item).isEnabled = false启用或禁用菜单项时,文本会自动改变颜色,任何使用颜色?attr/colorControlNormal的图标也会自动改变颜色。
我的菜单项是材质工具栏的一部分。此答案可能对其他类型的工具栏/应用栏有所帮助,但您的里程可能会有所不同。在我的活动中,我有这样的事情:
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="@style/ThemeOverlay.MaterialComponents.Toolbar.Surface"/>
我使用的主题看起来像这样:
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimary">@color/blue</item>
<item name="colorSecondary">@color/green</item>
<item name="colorSurface">@color/lightGrey</item>
<item name="colorOnSurface">@color/black</item>
[...]
<item name="windowActionModeOverlay">true</item>
</style>
您在按钮和菜单项(以及其他任何地方)中使用的图标的默认颜色也应该是?attr/colorControlNormal。因此,例如,我可能有一个看起来像这样的矢量图像:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal"
android:tintMode="src_atop">
<path android:pathData="..." android:fillColor="@android:color/white"/>
</vector>
如果您从Material Icons 下载图标,您会看到它们都使用 colorControlNormal。
如果你回头看我工具栏的定义,你会发现它使用了 ThemeOverlay ThemeOverlay.MaterialComponents.Toolbar.Surface,它被定义为:
<style name="ThemeOverlay.MaterialComponents.Toolbar.Surface" parent="">
<item name="colorControlNormal">@color/material_on_surface_emphasis_medium</item>
<item name="actionMenuTextColor">@color/material_on_surface_emphasis_medium</item>
</style>
这会将菜单项文本颜色和图标颜色设置为@color/material_on_surface_emphasis_medium,它不会响应是否启用。 @color/material_on_surface_emphasis_medium 看起来像:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="@dimen/material_emphasis_medium" android:color="?attr/colorOnSurface"/>
</selector>
(您可能改用ThemeOverlay.MaterialComponents.Toolbar.Primary,它有类似的问题 - 它只是使用colorOnPrimary。)
我们需要用我们自己的响应启用状态的颜色状态列表来替换它。因此,创建一个新文件res/color/menu_item_selector.xml,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true" android:alpha="@dimen/material_emphasis_medium" android:color="?attr/colorOnSurface"/>
<item android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorOnSurface"/>
</selector>
您看到我使用了与材质库相同的约定,即使用它们的常量来定义 alpha 值,并且我使用了colorOnSurface 作为我的颜色。如果您使用的是ThemeOverlay.MaterialComponents.Toolbar.Primary,您将需要colorOnPrimary。当然,您可以在这里使用任何颜色或 alpha,这取决于您。
现在在res/values/styles.xml 中创建一个新的 ThemeOverlay 来指向这个选择器,继承自您使用的任何 ThemeOverlay:
<!-- Toolbar - overrides the menu text color to use a selector that responds to whether it's enabled or not -->
<style name="ThemeOverlay.MyTheme.Toolbar" parent="ThemeOverlay.MaterialComponents.Toolbar.Surface">
<!-- Color used in the icons of menu actions (i.e. non-overflow menu items). This is just convention, this will affect anything that uses ?attr/colorControlNormal) -->
<item name="colorControlNormal">@color/menu_item_color_selector</item>
<!-- Color used in the text of menu actions (i.e. non-overflow menu items) -->
<item name="actionMenuTextColor">@color/menu_item_color_selector</item>
</style>
现在我们终于可以将这个ThemeOverlay 应用到工具栏了:
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="@style/ThemeOverlay.MyTheme.Toolbar"/>
【讨论】:
setEnabled(false) 在 API Level < 14 上运行良好,但在 14 上仍可点击。
【讨论】:
我在使用 MaterialComponents 主题的现代 android 上遇到了困难。我的问题是我在styles.xml 中设置了<item name="actionMenuTextColor">@color/blue</item>,无论项目是启用还是禁用,这都会覆盖文本颜色。解决办法是直接设置Color state list而不是颜色。
我的样式属性现在看起来像:
<item name="actionMenuTextColor">@color/menu_color_selector</item>
【讨论】:
actionMenuTextColor 对我没有任何影响(我将其设置为粉红色,但在任何地方都看不到粉红色)。如果看到这个的人仍然对 Material 组件有疑问,请查看我的回答 stackoverflow.com/a/66248473/5437033。
看看这个link
setEnabled 也可用于MenuItems。
【讨论】:
这是一个简单的方法(使用 Kotlin):
fun changeMenuItemColour(enabled: Boolean) {
var menuItem = SpannableString(mCustomToolbar?.menu?.findItem(R.id.some_menu_item)?.title)
var style = activity?.resources?.getColor(R.color.darkGraphite)!!
if (enabled) style = activity?.resources?.getColor(R.color.black)!!
menuItem.setSpan(ForegroundColorSpan(style), 0, menuItem.length, 0)
}
【讨论】: