如何使用Java编程来动态更改导航抽屉中所选菜单项的文本和图标颜色

29

我是Android开发的初学者。使用Android默认的导航抽屉活动,我正在开发一个应用程序。这个应用程序的要求之一是在运行时随机更改布局的背景颜色(包括导航抽屉标头颜色)。

现在除了导航抽屉上选择菜单项的颜色仍然是蓝色之外,其他一切都很顺利,像这样:

enter image description here

现在我的要求是,当其他布局的背景颜色为粉色时,导航栏上选择的菜单项也应该是粉色(我是指文本颜色和图标应该是粉色),像这样:

enter image description here

请问有人可以告诉我如何在代码中以编程方式实现它,因为我必须随机更改选定文本和图标的颜色。

这是菜单xml文件供参考:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">


    <group android:checkableBehavior="single">
        <item
                android:id="@+id/nav_quiz_all"
                android:icon="@drawable/ic_public_black_24dp"
                android:checked="true"
                android:title="All Countries Quiz"/>
        <item
                android:id="@+id/nav_quiz_bookmarked"
                android:icon="@drawable/ic_favorite_black_24dp"
                android:title="Favorite Quiz"/>
    </group>


    <item android:title="Communicate">
        <menu>
            <item
                android:id="@+id/nav_rate"
                android:icon="@drawable/ic_star_black_24dp"
                android:title="Rate this app"/>
            <item
                android:id="@+id/nav_share"
                android:icon="@drawable/ic_share_black_24dp"
                android:title="Share"/>
            <item
                android:id="@+id/nav_feedback"
                android:icon="@drawable/ic_feedback_black_24dp"
                android:title="Feedback"/>
            <item
                android:id="@+id/nav_about"
                android:icon="@drawable/ic_info_black_24dp"
                android:title="About"/>
        </menu>
    </item>


    <item
        android:id="@+id/nav_settings"
        android:icon="@drawable/ic_settings_black_24dp"
        android:title="Settings"/>

</menu>
5个回答

58

首先检查下面的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"
        android:fitsSystemWindows="true"
        android:background="@color/white"
        app:itemIconTint="@drawable/drawer_item_color"
        app:itemTextColor="@drawable/drawer_item_color"
        app:headerLayout="@layout/nav_header_main"
        app:menu="@menu/activity_main_drawer" />

检查这两件事

app:itemIconTint="@drawable/drawer_item_color"
app:itemTextColor="@drawable/drawer_item_color"

这两个标签都使用名为drawer_item_color.xml的选择器,它位于drawable文件夹中,下面是它的代码:

这里是原始代码,不做翻译。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/pink" android:state_checked="true" />
    <item android:color="@color/black" />
</selector>

使用选择器并添加您想要的颜色,这将为您完成工作。


1
选择器通常是处理这种情况的最佳方式...但他想要进行“随机”颜色更改...这需要在活动代码中解决...无论如何,对于全面的解释点赞。 - me_
感谢详细的解释,Abid :) 但问题是我想在运行时使用Java完成所有这些操作。我的应用程序在运行时随机更改其主题颜色,因此我需要在运行时更改所选菜单项文本和图标颜色以匹配主题颜色。有任何关于如何在运行时使用Java实现它的想法吗? - Kuldeep Kumar
2
讲解得很好,但是 app:itemIconTint() 不能访问 drawable 资源,它只能访问颜色。 - Waseem

16

第一种方法

尝试使用:

app:itemIconTint="@color/color_pink"  //selected icon color
app:itemTextColor="@color/color_pink" //selected text color
app:itemBackground="@color/color_gray" 

针对您的NavigationView

<android.support.design.widget.NavigationView
android:id="@+id/navigation_drawer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/header_layout"
app:itemIconTint="@color/color_pink"  
app:itemTextColor="@color/color_pink" 
app:itemBackground="@color/color_gray"
app:menu="@menu/menu_drawer" />

第二种方法

以编程方式进行更改,请使用:

navigationView.setItemTextColor(ColorStateList1);
navigationView.setItemIconTintList(ColorStateList2);

定义ColorStateList1ColorStateList2:

用于导航视图项文本颜色。

int[][] state = new int[][] {
        new int[] {-android.R.attr.state_enabled}, // disabled
        new int[] {android.R.attr.state_enabled}, // enabled
        new int[] {-android.R.attr.state_checked}, // unchecked
        new int[] { android.R.attr.state_pressed}  // pressed

};

int[] color = new int[] {
        Color.WHITE,
        Color.BLUE,
        Color.WHITE,
        Color.WHITE
};

ColorStateList ColorStateList1 = new ColorStateList(state, color);

导航视图项目图标颜色

int[][] states = new int[][] {
        new int[] {-android.R.attr.state_enabled}, // disabled
        new int[] {android.R.attr.state_enabled}, // enabled
        new int[] {-android.R.attr.state_checked}, // unchecked
        new int[] { android.R.attr.state_pressed}  // pressed

};

int[] colors = new int[] {
        Color.WHITE,
        Color.BLUE,
        Color.WHITE,
        Color.WHITE
};

ColorStateList ColorStateList2 = new ColorStateList(states, colors);

实际上我想在运行时做到这一点..有什么想法如何在Java中以编程方式实现它? - Kuldeep Kumar
谢谢你的编辑 :) .. 我对安卓还不太熟悉 .. 如果你能更详细地解释一下ColorStateList就太好了 ... 不管怎样,对你的回答点赞 :) - Kuldeep Kumar
在互联网上搜索后,我发现ColorStateList是一个包含选择器的XML资源文件。因此,我认为我需要在XML中预定义颜色,但这并不是我想要的,因为颜色需要在运行时动态更改。这些颜色是随机生成的 :( - Kuldeep Kumar

13

首先,非常感谢大家提供的解决方案 :) 借鉴上述答案并对 ColorStateList 进行了一些研究之后,我终于成功创建了一个方法,将导航抽屉中选中项的颜色设置为与我应用程序主题颜色相匹配,该主题颜色在运行时随机生成。

以下是这个方法:

public void setNavMenuItemThemeColors(int color){
    //Setting default colors for menu item Text and Icon
    int navDefaultTextColor = Color.parseColor("#202020");
    int navDefaultIconColor = Color.parseColor("#737373");

    //Defining ColorStateList for menu item Text
    ColorStateList navMenuTextList = new ColorStateList(
            new int[][]{
                    new int[]{android.R.attr.state_checked},
                    new int[]{android.R.attr.state_enabled},
                    new int[]{android.R.attr.state_pressed},
                    new int[]{android.R.attr.state_focused},
                    new int[]{android.R.attr.state_pressed}
            },
            new int[] {
                    color,
                    navDefaultTextColor,
                    navDefaultTextColor,
                    navDefaultTextColor,
                    navDefaultTextColor
            }
    );

    //Defining ColorStateList for menu item Icon
    ColorStateList navMenuIconList = new ColorStateList(
            new int[][]{
                    new int[]{android.R.attr.state_checked},
                    new int[]{android.R.attr.state_enabled},
                    new int[]{android.R.attr.state_pressed},
                    new int[]{android.R.attr.state_focused},
                    new int[]{android.R.attr.state_pressed}
            },
            new int[] {
                    color,
                    navDefaultIconColor,
                    navDefaultIconColor,
                    navDefaultIconColor,
                    navDefaultIconColor
            }
    );

    mNavView.setItemTextColor(navMenuTextList);
    mNavView.setItemIconTintList(navMenuIconList);
}

您可以使用任何int color调用此方法:)


很好的解释。 - Kavin Varnan
好的,谢谢。 - Mahesh Kavathiya

4
我已经在sdk 17到sdk 26上测试了这段代码。代码在以下部分编写逻辑:
   setContent(R.layou.your_activity)

通过ID查找导航视图

 private void setupNavigationSelection(NavigationView navigationViewList) {


    /* note : warning don't use other attribute  just checked and unchecked else         wont work*/
    int[][] states = new int[][]{
            new int[]{android.R.attr.state_checked}, // checked
            new int[]{-android.R.attr.state_checked} // unchecked
    };
    int[] colors = new int[]{
            Color.RED
            Color.GREEN,
    };

    LayerDrawable layerDrawable = getSideBarDrawable(0x80dedede);
    StateListDrawable arrowImgStates = new StateListDrawable();
    Drawable normalDrawable = new ColorDrawable(Color.TRANSPARENT);;
    arrowImgStates.addState(new int[]{android.R.attr.state_pressed}, normalDrawable);
    arrowImgStates.addState(new int[]{android.R.attr.state_focused}, layerDrawable);
    arrowImgStates.addState(new int[]{android.R.attr.state_selected}, layerDrawable);
    arrowImgStates.addState(new int[]{android.R.attr.state_checked}, layerDrawable);
    arrowImgStates.addState(new int[]{}, normalDrawable);

    ColorStateList colorStateList = new ColorStateList(states, colors);
    navigationViewList.setItemTextColor(colorStateList);
    navigationViewList.setItemIconTintList(colorStateList);
    navigationViewList.setItemBackground(arrowImgStates);

}

public LayerDrawable getSideBarDrawable(int bgColor) {
    int iSize = CLViewUtil.dpToPx(6);
    GradientDrawable gradientDrawable = new GradientDrawable();
    gradientDrawable.setShape(GradientDrawable.RECTANGLE);
    gradientDrawable.setStroke(iSize, CLThemeUtil.getThemePrimaryColor(this));
    gradientDrawable.setColor(bgColor);
    LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{gradientDrawable});
    layerDrawable.setLayerInset(0, 0, -iSize, -iSize, -iSize);
    return layerDrawable;

}

1
你尝试过了吗?
mNavigationView.setItemTextColor(yourColorStateList);

感谢您的回答Silva。如果我错了,请纠正我,但我认为ColorSateList是一个选择器XML资源文件,需要预定义颜色。但在我的应用程序中,颜色需要在运行时动态更改。颜色是随机生成的:( - Kuldeep Kumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接