是否有可能在Android中灰显(而不仅仅是禁用)一个MenuItem?

时间:2012-03-10 01:02:22

标签: android menu menuitem

有一个问题是相同的功能on Blackberry,并且有一些不同的线程引用了这个bug(据我所知,它已经被关闭而没有解决方案),但我还没有找到一个专门为Android。

我根据某些状态在某些MenuItem上调用setEnabled(false),但它们在视觉上看起来相同。我希望它们以某种方式被抵消,以便用户知道当前的选项不可用 - 有没有办法做到这一点?

9 个答案:

答案 0 :(得分:61)

在所有Android版本中,最简单的方法是使用它来显示菜单操作图标为禁用并将其设为FUNCTION:

@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);
    }
}

答案 1 :(得分:56)

我有同样的问题。有两种方法可以实现这一点:

  1. 将您的图标放在StateList中,以便在禁用
  2. 时使用不同的图标
  3. 我现在用的是什么。在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);
    }
    
  4. 您可以拨打invalidateOptionsMenu()(或从ABS,supportInvalidateOptionsMenu())来重建菜单。

    编辑:更新了解决方案2

    来源:https://groups.google.com/forum/?fromgroups#!topic/actionbarsherlock/Z8Ic8djq-3o

答案 2 :(得分:8)

我找到了一种使用drawable选择器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会随着状态而变化!

答案 3 :(得分:2)

setEnabled(false)API Level < 14上正常工作,但14项仍可点击。

答案 4 :(得分:2)

我这样做的方法是使用&#34; itemIconTint&#34;在NavigationView中,您还可以使用&#34; itemTextColor&#34;

使文本变灰。

这是Navigationview:

<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" />

和&#34; @ color / menu_text_color&#34;是一个选择器:

<?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);

完成!

答案 5 :(得分:1)

看看这个link

setEnabled也可用于MenuItems

答案 6 :(得分:1)

这是一个简单的方法(使用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)
}

答案 7 :(得分:1)

我遇到了一个问题,即我的文字和图标都没有明显变化。其他答案要么对我不起作用,要么不是很优雅。这是适用于最新 Material recommendations 的答案。

应该能够在menu.findItem(R.id.menu_my_item).isEnabled = false中简单地调用onPrepareOptionsMenu(menu: Menu)

(如果您需要 onPrepareOptionsMenu 再次运行,您可以简单地调用 invalidateOptionsMenu()activity?.invalidateOptionsMenu()(来自片段),应用程序会将要重新创建的菜单排入队列。或者您可以将菜单项存储在成员变量中以供日后修改,但请注意在 onDestroyOptionsMenu 内销毁对它的引用以避免内存泄漏。)

菜单项被禁用的事实应该足以使文本或图标自动变灰。困难在于设置您的样式以使其有效。

简答

首先创建一个您希望图标和文本使用的颜色状态列表 my_color_state_list.xml(例如,启用时为黑色,禁用时为灰色)。 (有关示例,请参阅完整答案。)

如果您使用的是 com.google.android.material.appbar.MaterialToolbar,您可以通过提供自定义主题叠加层来告诉它将此选择器用于图标和文本。在您的 Activity 的 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"/>

答案 8 :(得分:0)

在具有MaterialComponents主题的现代android上,我遇到了困难。我的问题是我在<item name="actionMenuTextColor">@color/blue</item>中设置了styles.xml,无论该项目是启用还是禁用,这都会覆盖文本颜色。解决方案是设置Color state list而不是直接设置颜色。

我的样式属性现在看起来像:

<item name="actionMenuTextColor">@drawable/menu_color_selector</item>