Как настроить фон элемента и цвет текста элемента в NavigationView?

Я хочу достичь чего-то подобного, что показано в Документах по дизайну материалов.

colorControlHighlight используется для фона на отмеченных пунктах.

Мне нужно настроить:

  • фон не проверен
  • цвет текста проверен
  • цвет текста снят

7 ответов

Решение

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)

Опция фона требует рисоваемого ресурса вместо цвета, каждая попытка установить цвет заканчивается исключением. Ресурс Drawable должен быть создан в 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);

Если элементы не будут установлены как проверяемые, фон не будет работать (цвет текста и значков будет работать как положено).

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,

пример

Создайте новый *.xml файл в /res/color - давайте назовем это 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 ожидает идентификатор ресурса. Смотрите также документы.

В библиотеке MaterialComponents вы можете использовать эти атрибуты:

  • 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 использовать фигурный фон, программно созданный NavigationView когда itemShapeAppearance и / или itemShapeAppearanceOverlayустановлено (поведение по умолчанию).
Этот фон оформлен с использованиемitemShape*атрибуты.
НастройкаitemBackground перезапишет программный фон и приведет к игнорированию значений, установленных в атрибутах itemShape*.

Использование colorControlHighlight является хорошим решением для меня. Имейте в виду, что с помощью последней библиотеки поддержки вы можете определить тему (а не только стиль) для каждого виджета; например, вы можете определить colorControlHighlight в теме NavigationView, и это не будет применяться к остальным виджетам.

Если вы хотите изменить только один цвет пункта меню из вашей деятельности, основанной на событиях, посмотрите этот блог от 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);

Вы можете программно использовать этот код:

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

Теперь в режиме навигации вы также можете предоставить свой собственный вид элемента. С новым 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 как пожелаешь. Надеюсь, что это было полезно:) Источник

Если вы хотите сделать это программно:

На основании ответа Джона:

Вы можете использовать расширение 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)

Вы можете сделать это, используя следующее утверждение:

navigationView.setItemBackground(ContextCompat.getDrawable(CustomerHomeActivity.this, R.color.transparent));
Другие вопросы по тегам