【问题标题】:Is it possible to grey out (not just disable) a MenuItem in Android?是否可以在 Android 中灰显(不仅仅是禁用)MenuItem?
【发布时间】:2012-03-27 10:20:57
【问题描述】:

对于 on Blackberry 的相同功能有一个问题,还有几个不同的线程引用了这个 bug(据我所知,它已经关闭,没有解决方案),但我还没有找到一个专门用于安卓。

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

【问题讨论】:

    标签: android menu menuitem


    【解决方案1】:

    在所有 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);
        }
    }
    

    【讨论】:

    • 这正是我想要的。
    • 是的,这对我有用,很高兴能够保留原始图标。
    • 注意:如果这个图标被使用了,请确保在设置 alpha 之前先对其进行 mutate() ,否则所有使用这个 drawable 的地方都会被调整,这不一定是人们想要的。跨度>
    • 有没有其他方法可以设置alpha值?(内部样式)
    • 注意,这仅在您的 MenuItem 是图标时有效。不适用于纯文本菜单项。
    【解决方案2】:

    我遇到了同样的问题。有两种方法可以让它工作:

    1. 将您的图标放在 StateList 中,以便在禁用时使用不同的图标
    2. 我现在用的。在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

    【讨论】:

    • 这真的会改变菜单项文本/标题的颜色吗?也就是说,它会变灰吗?据我了解,这只会影响图标。如果没有图标而只有文字怎么办?
    • 调用 item.setEnabled() 已经使文本看起来变灰了。问题是在操作栏上的文本是灰色的,但图标不是 - 此代码将其变为灰色。
    • Nobu Games 对您链接到的 Google 群组主题的回复在 Jelly Bean 中对我很有帮助:menuItem.getIcon().setAlpha(enabled ? 255 : 64);
    【解决方案3】:

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

    【讨论】:

    • 此解决方案仅适用于 Android 5.0+ (API 21+) Lollipop 及更高版本,因此在早期版本中需要 setColorFilter。
    • 与仅准备 2 种不同颜色的图标并交换它们相比,这有多贵?
    • @Ryuu 用户矢量可绘制并更改颜色。而不是两个 PNG 文件
    【解决方案4】:

    我的做法是在 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);
    

    完成!

    【讨论】:

      【解决方案5】:

      我遇到了一个问题,即我的文本和图标都没有明显变化。其他答案要么对我不起作用,要么不是很优雅。这是适用于最新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"/>
      

      【讨论】:

        【解决方案6】:

        setEnabled(false)API Level &lt; 14 上运行良好,但在 14 上仍可点击。

        【讨论】:

        • 这个答案与问题有关吗?
        【解决方案7】:

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

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

        &lt;item name="actionMenuTextColor"&gt;@color/menu_color_selector&lt;/item&gt;

        【讨论】:

        • 我遇到了完全相同的问题。谢谢!
        • 我遇到了同样的问题,但actionMenuTextColor 对我没有任何影响(我将其设置为粉红色,但在任何地方都看不到粉红色)。如果看到这个的人仍然对 Material 组件有疑问,请查看我的回答 stackoverflow.com/a/66248473/5437033
        【解决方案8】:

        看看这个link

        setEnabled 也可用于MenuItems

        【讨论】:

        • 是的,我正在使用 setEnabled,但它不会在视觉上改变它。
        • 试试下面的代码 public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, 1, 1, "Test").setEnabled(false);返回 super.onCreateOptionsMenu(menu); }
        • 当您说它工作正常时,您的意思是它正在将文本更改为灰色吗?还是只是它被禁用了?我正在尝试做第一个。
        • 这将是android的默认禁用菜单项,无法选择,普通Android用户可以轻松识别和知道。
        • 我知道它无法选择,但在视觉上它看起来完全一样。或者您是说它在视觉上可以识别为已禁用?
        【解决方案9】:

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

        【讨论】:

          猜你喜欢
          • 2021-06-07
          • 1970-01-01
          • 2020-11-17
          • 1970-01-01
          • 2018-07-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-11-30
          相关资源
          最近更新 更多