【问题标题】:How to customize item background and item text color inside NavigationView?如何在 NavigationView 中自定义项目背景和项目文本颜色?
【发布时间】:2015-08-16 02:58:55
【问题描述】:

我想实现Material Design Docs 中所示的类似目标。

colorControlHighlight 用于选中项目的背景。

我需要自定义:

  • 背景未选中
  • 已检查文本颜色
  • 未选中文本颜色

【问题讨论】:

    标签: android material-design drawerlayout android-design-library navigationview


    【解决方案1】:

    itemBackgrounditemIconTintitemTextColor 是可以设置的简单 xml 属性,但您必须使用自定义前缀而不是 android:

    示例

    <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">
    
        <!-- Other layout views -->
    
        <android.support.design.widget.NavigationView
            android:id="@+id/nav_view"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:fitsSystemWindows="true"
            app:itemBackground="@drawable/my_ripple"
            app:itemIconTint="#2196f3"
            app:itemTextColor="#009688"
            app:headerLayout="@layout/nav_header"
            app:menu="@menu/drawer_view" />
    
    </android.support.v4.widget.DrawerLayout>
    

    注意:在这种情况下,文本颜色、图标色调和背景是静态的。如果您想更改文本的颜色(例如,未选中时为粉红色,选中时为青色),您应该使用ColorStateList

    示例

    /res/color 中创建一个新的 *.xml 文件 - 我们将其命名为 state_list.xml - 具有以下内容:

    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- This is used when the Navigation Item is checked -->
        <item android:color="#009688" android:state_checked="true" />
        <!-- This is the default text color -->
        <item android:color="#E91E63" />
    </selector>
    

    然后像这样简单地引用它:app:itemTextColor="@color/state_list"

    itemIconTint 也是如此。 itemBackground 需要一个资源 ID。另请参阅docs

    【讨论】:

    • 选中项目中的项目背景只需使用 #123456
    • 没错,但这也可能改变其他视图的颜色,例如EditText,至少如果你在全局主题中定义它。
    • 有人在设置app:itemBackground="@drawable/my_ripple"时遇到问题吗?我碰巧当我按下一个项目时,最底部的那个反映了涟漪效应,而不是我实际按下的那个。
    • @JavierMendonca 我也有同样的经历,但我不知道如何解决这个 atm 问题——这很可能是一个错误,但也许值得针对这个特定问题提出一个单独的问题。
    • 请记住,要使pressed工作,您需要将其从android:state_checked更改为android:state_pressed。
    【解决方案2】:

    NavigationDrawer(NavigationView) 有三个选项用于配置选中/选中项。

    app:itemIconTint="@color/menu_text_color" //icon color
    app:itemTextColor="@color/menu_text_color" //text color
    app:itemBackground="@drawable/menu_background_color" //background
    

    图标和文字颜色

    前两个选项(图标和文本)需要颜色状态列表资源 - https://developer.android.com/guide/topics/resources/color-list-resource.html

    此类menu_text_color 资源需要在res/color 中创建。此文件内容应类似于:

    <!-- res/color/menu_text_color.xml -->
    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
      <item android:color="@color/colorWhite" android:state_checked="true" />
      <item android:color="@color/colorBlack" android:state_checked="false"/>
    </selector>
    
    • @color/colorWhite - 用于检查项目的颜色资源

    • @color/colorBlack - 用于未选中项的颜色资源

    我为两者创建了一个资源,但可以创建两个单独的文件 - 一个用于文本,一个用于图标。

    背景(itemBackground)

    背景选项需要可绘制资源而不是颜色,每次尝试设置颜色都会以异常结束。可绘制资源需要在 res/drawable 中创建,其内容应类似于:

    <!-- res/drawable/menu_background_color.xml -->
    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
      <item android:drawable="@android:color/transparent"  android:state_checked="false"/>
      <item android:drawable="@color/colorPrimary" android:state_checked="true"/>
    </selector>
    

    不需要创建任何模拟颜色的可绘制对象(在其他解决方案中我看到了这样的提议 - 可能是旧的 sdk 版本),颜色可以直接在这个文件中使用。在这个示例文件中,我对未选中的项目使用透明色,对已选中的项目使用colorPrimary

    疑难解答和重要说明

    • 在后台资源中始终使用 state_checked="false" 而不是默认值,默认颜色将不起作用
    • 对于动态/以编程方式创建的菜单记得将项目设置为可检查

    代码示例(动态菜单项添加):

      menu.add(group_id, item_id, Menu.NONE, item_name).setCheckable(true).setChecked(false);
    

    如果项目未设置为可检查,则背景将不起作用(令人惊讶的文本和图标颜色将按预期工作)。

    【讨论】:

    • 很好的答案,但我更喜欢为导航视图创建一个主题。我需要覆盖哪个属性?
    • @MaciejSikora 你救了我的命!我爱你们男人!嫁给我:)
    • 这是最重要的,否则没有任何作用。 remember to set items as checkable。感谢您提到这一点,没有人这样做。
    【解决方案3】:

    通过MaterialComponents Library,您可以使用这些属性:

    • app:itemShapeFillColor:背景项目颜色
    • app:itemIconTint:图标色调
    • app:itemTextColor:文字颜色

    在布局中:

    <com.google.android.material.navigation.NavigationView
        app:itemShapeFillColor="@color/shape_selector"
        app:itemIconTint="@color/icon_tint_selector"
        app:itemTextColor="@color/text_color_selector"
        ../>
    

    在自定义样式中:

    <style name="..." parent="Widget.MaterialComponents.NavigationView" >
       <item name="itemShapeFillColor">@color/shape_selector</item>
       <item name="itemIconTint">@color/icon_tint_selector</item>
       <item name="itemTextColor">@color/text_color_selector</item>
    </style>
    

    对于itemIconTintitemTextColor,您可以使用这样的选择器:

    <selector xmlns:android="http://schemas.android.com/apk/res/android">
      <item android:color="?attr/colorPrimary" android:state_checked="true"/>
      <item android:alpha="0.38" android:color="?attr/colorOnSurface" android:state_enabled="false"/>
      <item android:color="?attr/colorOnSurface"/>
    </selector>
    

    对于itemShapeFillColor,您可以使用如下选择器:

    <selector xmlns:android="http://schemas.android.com/apk/res/android">
      <item android:alpha="0.12" android:color="?attr/colorPrimary" android:state_activated="true"/>
      <item android:alpha="0.12" android:color="?attr/colorPrimary" android:state_checked="true"/>
      <item android:color="@android:color/transparent"/>
    </selector>
    

    只是一个最后的说明。 注意使用itemBackground
    当设置itemShapeAppearance 和/或itemShapeAppearanceOverlay 时,设置为@null 以使用由NavigationView 以编程方式生成的形状背景(默认行为)。此背景使用itemShape* 属性设置样式。
    设置 itemBackground 将覆盖编程背景并导致 itemShape* 属性中设置的值被忽略。

    【讨论】:

      【解决方案4】:

      使用 colorControlHighlight 对我来说是一个很好的解决方案。请注意,使用最新的支持库,您可以为每个小部件定义一个主题(不仅仅是样式);例如,您可以将 colorControlHighlight 定义到 NavigationView 主题中,这不会应用于其余的小部件。

      【讨论】:

      • 完美答案,但我需要在 NavigationView 主题中覆盖哪些属性来控制背景、文本颜色和图标颜色?
      • 是的,当然,使用&lt;item name="android:colorControlHighlight"&gt;@color/navigationDrawerTextNight&lt;/item&gt; 创建一个样式,但它是如何应用于菜单项文本的? itemTextColor 不存在于样式中
      【解决方案5】:

      如果您只想根据事件更改活动中的一种菜单项颜色,请参阅 HANIHASHEMI 的此博客:

      https://hanihashemi.com/2017/05/06/change-text-color-of-menuitem-in-navigation-drawer/

      private void setTextColorForMenuItem(MenuItem menuItem, @ColorRes int color) {
        SpannableString spanString = new SpannableString(menuItem.getTitle().toString());
        spanString.setSpan(new ForegroundColorSpan(ContextCompat.getColor(this, color)), 0, spanString.length(), 0);
        menuItem.setTitle(spanString);
      }
      

      调用方法

      setTextColorForMenuItem(item, R.color.colorPrimary);
      

      如果您使用 Xamarin Android,请尝试以下操作:

      private void SetTextColorForMenuItem(IMenuItem menuItem, Android.Graphics.Color color)
              {
                  SpannableString spanString = new SpannableString(menuItem.TitleFormatted.ToString());
                  spanString.SetSpan(new ForegroundColorSpan(color), 0, spanString.Length(), 0);
                  menuItem.SetTitle(spanString);
              }
      

      调用方法:

      SetTextColorForMenuItem(navigationView.Menu.GetItem(0), Android.Graphics.Color.OrangeRed);
      

      【讨论】:

        【解决方案6】:

        您可以通过编程方式使用此代码:

        int[][] states = new int[][] {
            new int[] { android.R.attr.state_enabled}, // enabled
            new int[] {-android.R.attr.state_enabled}, // disabled
            new int[] {-android.R.attr.state_checked}, // unchecked
            new int[] { android.R.attr.state_pressed}  // pressed
        };
        
        int[] colors = new int[] {
            Color.BLACK,
            Color.RED,
            Color.GREEN,
            Color.BLUE
        };
        
        ColorStateList myList = new ColorStateList(states, colors);
        
          nav_view.setItemIconTintList(myList);
        

        【讨论】:

          【解决方案7】:

          现在,在导航视图中,您还可以提供自己的项目视图。使用新的appcompat-v7:23.1.0,您可以

          通过 app:actionLayout 或使用 MenuItemCompat.setActionView() 为项目设置自定义视图。

          View view = View.inflate(context, R.layout.your_custom_nav_layout_item, null);
          MenuItemCompat.setActionView(menuItem, view); 
          

          通过这种方式,您可以使用 TextView 创建自己的布局,并根据需要更改 backgrounds/colors/fonts。希望这有帮助:) Source

          【讨论】:

            【解决方案8】:

            如果您想以编程方式执行此操作:

            根据 Jhon 的回答:

            你可以像这样使用 Kotlin 扩展:

            fun NavigationView.setTextColorForMenuItems(@ColorInt color: Int) {
                for (i: Int in 0 until menu.size()) {
                    val menuItem = menu.getItem(i)
                    val spanString = SpannableString(menuItem.title.toString())
                    spanString.setSpan(ForegroundColorSpan(color), 0, spanString.length, 0)
                    menuItem.title = spanString
                }
            }
            

            然后调用

            nav_view.setTextColorForMenuItems(Color.BLACK)
            

            【讨论】:

              【解决方案9】:

              您可以使用以下语句来做到这一点:

              navigationView.setItemBackground(ContextCompat.getDrawable(CustomerHomeActivity.this, R.color.transparent));
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2015-08-12
                • 1970-01-01
                • 1970-01-01
                • 2011-09-19
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多