如何在 NavigationView 中自定义项目背景和项目文本颜色?
How to customize item background and item text color inside NavigationView?
我想实现 Material Design Docs 中显示的类似内容。
colorControlHighlight
用于选中项目的背景。
我需要定制:
- 背景未检查
- 已检查文本颜色
- 未选中文本颜色
itemBackground
、itemIconTint
和 itemTextColor
是可以设置的简单 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。
使用 colorControlHighlight 对我来说是一个很好的解决方案。请注意,使用最新的支持库,您可以为每个小部件定义一个主题(而不仅仅是样式);例如,您可以将 colorControlHighlight 定义到 NavigationView 主题中,这将不会应用于其余的小部件。
您可以使用以下语句来完成:
navigationView.setItemBackground(ContextCompat.getDrawable(CustomerHomeActivity.this, R.color.transparent));
现在,在导航视图中,您还可以提供自己的项目视图。使用新 appcompat-v7:23.1.0
,您可以
set custom views for items via app:actionLayout or using MenuItemCompat.setActionView().
View view = View.inflate(context, R.layout.your_custom_nav_layout_item, null);
MenuItemCompat.setActionView(menuItem, view);
这样您就可以使用 TextView 创建自己的布局并根据需要更改 backgrounds/colors/fonts
。希望这有帮助:)
Source
您可以以编程方式使用此代码:
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);
NavigationDrawer(NavigationView) 有三个配置 checked/selected 项的选项。
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.
需要在 res/color 中创建此类 menu_text_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>
不需要创建任何模拟颜色的drawable(在其他解决方案中我看到了这样的命题——可能是针对旧的sdk版本),颜色可以直接在这个文件中使用。在此示例文件中,我对未选中的项目使用透明颜色,对选中的项目使用 colorPrimary
。
疑难解答和重要说明
- 在后台资源中始终使用 state_checked="false" 而不是默认值,使用默认颜色将不起作用
- 对于 dynamic/programmatically 创建的菜单 记得将项目设置为可检查:
代码示例(动态菜单项添加):
menu.add(group_id, item_id, Menu.NONE, item_name).setCheckable(true).setChecked(false);
如果项目未设置为可检查,则背景将无法工作(令人惊讶的文本和图标颜色将按预期工作)。
如果您只想根据事件更改 activity 中的一个菜单项颜色,请参阅 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);
如果您想以编程方式执行此操作:
根据 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)
通过 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>
对于 itemIconTint
和 itemTextColor
你可以使用这样的选择器:
<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
.
它设置为 @null
以在设置 itemShapeAppearance
and/or itemShapeAppearanceOverlay
时使用由 NavigationView
以编程方式生成的形状背景(默认行为)。
此背景使用 itemShape*
属性设置样式。
设置 itemBackground
将覆盖编程背景并导致在 itemShape* 属性中设置的值被忽略。
我想实现 Material Design Docs 中显示的类似内容。
colorControlHighlight
用于选中项目的背景。
我需要定制:
- 背景未检查
- 已检查文本颜色
- 未选中文本颜色
itemBackground
、itemIconTint
和 itemTextColor
是可以设置的简单 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。
使用 colorControlHighlight 对我来说是一个很好的解决方案。请注意,使用最新的支持库,您可以为每个小部件定义一个主题(而不仅仅是样式);例如,您可以将 colorControlHighlight 定义到 NavigationView 主题中,这将不会应用于其余的小部件。
您可以使用以下语句来完成:
navigationView.setItemBackground(ContextCompat.getDrawable(CustomerHomeActivity.this, R.color.transparent));
现在,在导航视图中,您还可以提供自己的项目视图。使用新 appcompat-v7:23.1.0
,您可以
set custom views for items via app:actionLayout or using MenuItemCompat.setActionView().
View view = View.inflate(context, R.layout.your_custom_nav_layout_item, null);
MenuItemCompat.setActionView(menuItem, view);
这样您就可以使用 TextView 创建自己的布局并根据需要更改 backgrounds/colors/fonts
。希望这有帮助:)
Source
您可以以编程方式使用此代码:
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);
NavigationDrawer(NavigationView) 有三个配置 checked/selected 项的选项。
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.
需要在 res/color 中创建此类 menu_text_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>
不需要创建任何模拟颜色的drawable(在其他解决方案中我看到了这样的命题——可能是针对旧的sdk版本),颜色可以直接在这个文件中使用。在此示例文件中,我对未选中的项目使用透明颜色,对选中的项目使用 colorPrimary
。
疑难解答和重要说明
- 在后台资源中始终使用 state_checked="false" 而不是默认值,使用默认颜色将不起作用
- 对于 dynamic/programmatically 创建的菜单 记得将项目设置为可检查:
代码示例(动态菜单项添加):
menu.add(group_id, item_id, Menu.NONE, item_name).setCheckable(true).setChecked(false);
如果项目未设置为可检查,则背景将无法工作(令人惊讶的文本和图标颜色将按预期工作)。
如果您只想根据事件更改 activity 中的一个菜单项颜色,请参阅 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);
如果您想以编程方式执行此操作:
根据 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)
通过 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>
对于 itemIconTint
和 itemTextColor
你可以使用这样的选择器:
<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
.
它设置为 @null
以在设置 itemShapeAppearance
and/or itemShapeAppearanceOverlay
时使用由 NavigationView
以编程方式生成的形状背景(默认行为)。
此背景使用 itemShape*
属性设置样式。
设置 itemBackground
将覆盖编程背景并导致在 itemShape* 属性中设置的值被忽略。