Изменить цвет отмеченного пункта меню в панели навигации

104

Я использую новую библиотеку поддержки дизайна Android, чтобы реализовать панель навигации в моем приложении.

Не могу понять, как изменить цвет выбранного предмета!

Вот xml меню:

<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
    <item
        android:id="@+id/navigation_item_1"
        android:icon="@drawable/ic_1"
        android:title="@string/navigation_item_1"/>

    <item
        android:id="@+id/navigation_item_2"
        android:icon="@drawable/ic_2"
        android:title="@string/navigation_item_2"/>
</group>

И вот xml-файл navigationview, который помещается внутри android.support.v4.widget.DrawerLayout:

<android.support.design.widget.NavigationView
    android:id="@+id/activity_main_navigationview"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    app:headerLayout="@layout/drawer_header"
    app:itemIconTint="@color/black"
    app:itemTextColor="@color/primary_text"
    app:menu="@menu/menu_drawer">

    <TextView
        android:id="@+id/main_activity_version"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:layout_marginBottom="@dimen/activity_vertical_margin"
        android:layout_marginLeft="@dimen/activity_horizontal_margin"
        android:textColor="@color/primary_text" />

</android.support.design.widget.NavigationView>

Спасибо за помощь !

[РЕДАКТИРОВАТЬ] Я уже рассматривал такие решения, как это: Изменить цвет фона меню Android .

Это похоже на хитрость, и я подумал, что с новой библиотекой поддержки дизайна можно было бы добавить что-то более чистое?

Грег
источник
возможный дубликат изменения цвета фона меню Android
jlopez

Ответы:

246

Вы можете добиться этого с помощью ресурса Color State Resource . Если вы заметили внутри NavigationViewсебя, вы используете

app:itemIconTint="@color/black"
app:itemTextColor="@color/primary_text"

Здесь вместо использования @color/blackили @color/primary_testиспользуйте Color State List Resource. Для этого сначала создайте новый xml(например, drawer_item.xml) внутри colorкаталога (который должен находиться внутри resкаталога). Если у вас еще нет каталога с именем color, создайте его.

Теперь внутри drawer_item.xmlсделай что-нибудь вроде этого

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="checked state color" android:state_checked="true" />
    <item android:color="your default color" />
</selector>

Последним шагом будет изменение вашего NavigationView

<android.support.design.widget.NavigationView
    android:id="@+id/activity_main_navigationview"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    app:headerLayout="@layout/drawer_header"
    app:itemIconTint="@color/drawer_item"  // notice here
    app:itemTextColor="@color/drawer_item" // and here
    app:itemBackground="@android:color/transparent"// and here for setting the background color to tranparent
    app:menu="@menu/menu_drawer">

Как это можно использовать отдельные цвета список состояний Ресурсы IconTint, ItemTextColor, ItemBackground.

Теперь, когда вы устанавливаете элемент как отмеченный (внутри xmlили программно), конкретный элемент будет иметь другой цвет, чем те, которые не отмечены.

Створка_КП
источник
Помните, что для того, чтобы нажатие работало, вам нужно изменить его с android: state_checked на android: state_pressed.
Programista
33
для ItemBackground вам нужно использовать рисование вместо цвета, потому что вы не можете определить фон с помощью цветового ресурса.
сэр Фанкенстайн,
@sash, если мы хотим изменить изображение значка при выборе элемента навигации, как мы это сделаем?
mohit
@sirFunkenstine Если вы используете селектор цвета, вы можете поместить его в папку цветов в папке res.
Кишан Вагела
@KishanVaghela делает то, что вы предлагаете, приводит к этой ошибке: двоичный файл XML, строка №3: ​​тег <item> требует атрибута 'drawable' или дочернего тега, определяющего возможность рисования
iOSAndroidWindowsMobileAppsDev
67

Я считаю, app:itemBackgroundчто ожидает рисования. Итак, следуйте инструкциям ниже:

Создайте файл highlight_color.xmlс возможностью рисования со следующим содержимым:

<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
     <solid android:color="YOUR HIGHLIGHT COLOR"/>
</shape>

Создайте еще один файл nav_item_drawable.xmlсо следующим содержимым:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@drawable/highlight_color" android:state_checked="true"/>
</selector>

Наконец, добавьте app:itemBackgroundтег в NavView:

<android.support.design.widget.NavigationView
android:id="@+id/activity_main_navigationview"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/drawer_header"
app:itemIconTint="@color/black"
app:itemTextColor="@color/primary_text"
app:itemBackground="@drawable/nav_item_drawable"
app:menu="@menu/menu_drawer">

здесь файл highlight_color.xml определяет сплошной цвет фона. Позже этот цвет для рисования назначается селектору nav_item_drawable.xml.

Это сработало для меня. Надеюсь, это поможет.

******************************************** ОБНОВЛЕНО *** ******************************************

Хотя вышеупомянутый ответ дает вам точный контроль над некоторыми свойствами, но способ, который я собираюсь описать, кажется более ТВЕРДЫМ и немного КЛАССНЫМ .

Итак, что вы можете сделать, вы можете определить ThemeOverlay в styles.xmlдля NavigationView следующим образом:

    <style name="ThemeOverlay.AppCompat.navTheme">

        <!-- Color of text and icon when SELECTED -->
        <item name="colorPrimary">@color/color_of_your_choice</item> 

        <!-- Background color when SELECTED -->
        <item name="colorControlHighlight">@color/color_of_your_choice</item> 

    </style>

теперь примените этот ThemeOverlay к app:themeатрибуту NavigationView, например:

<android.support.design.widget.NavigationView
android:id="@+id/activity_main_navigationview"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:theme="@style/ThemeOverlay.AppCompat.navTheme"
app:headerLayout="@layout/drawer_header"
app:menu="@menu/menu_drawer">

Я надеюсь, это поможет.

Анкуш
источник
1
Кроме того, этот метод может использоваться как и android:background="@drawable/nav_item_drawable"для других виджетов, таких как RadioButton, Checkbox, Button и т. Д. Уменьшает количество ненужных программ для обработки setOnCheckedChangeListenerтолько для выделения цвета.
rupinderjeet
@Ankush, это работает, но текст и значок исчезают, я тоже установил цвет оттенка элемента, но он не работает. не могли бы вы подсказать мне, как это можно сделать?
Пользователь
1
@User Я не знаю, что пошло не так с вашим кодом, но я добавил к ответу. Совершенно другой способ добиться того же с меньшими усилиями. Вы можете это проверить.
Ankush
1
Это следует принять как ответ! Спасибо большое, очень помогли !!!
Светлана Рожкова
НЕ ЗАБУДЬТЕ ПРИМЕНИТЬ "CHECKABLE = TRUE" В ВАШЕМ МЕНЮ XML ДЛЯ ФОНА ДЛЯ РАБОТЫ НАДЛЕЖАЩЕЙ
Ankit
4

Каждый NavigateItemраз при NavigateViewнажатии элемента в

//listen for navigation events
NavigationView navigationView = (NavigationView)findViewById(R.id.navigation);
navigationView.setNavigationItemSelectedListener(this);
// select the correct nav menu item
navigationView.getMenu().findItem(mNavItemId).setChecked(true);

Добавить NavigationItemSelectedListenerвNavigationView

  @Override
  public boolean onNavigationItemSelected(final MenuItem menuItem) {
    // update highlighted item in the navigation menu
    menuItem.setChecked(true);
    mNavItemId = menuItem.getItemId();

    // allow some time after closing the drawer before performing real navigation
    // so the user can see what is happening
    mDrawerLayout.closeDrawer(GravityCompat.START);
    mDrawerActionHandler.postDelayed(new Runnable() {
      @Override
      public void run() {
        navigate(menuItem.getItemId());
      }
    }, DRAWER_CLOSE_DELAY_MS);
    return true;
  }
Викалп Патель
источник
Спасибо за помощь Викалп, но я уже этим занимаюсь ( setChecked(true)). Я вижу, как меняется цвет отмеченного элемента, но я не могу его изменить, цвет всегда является более светлой версией фона навигационного представления.
Грег
@Greg По умолчанию setChecked(true)на Viewизменения цвета фона Шифрование до темы , что устройство , которое использует. Если вы измените фон элемента на какой-либо другой цвет, вам нужно раздувать макет DrawerLayoutили NavigationViewи обрабатывать его самостоятельно.
Vikalp Patel
Еще раз спасибо, я попытался сделать то, что вы мне сказали, но безуспешно, не могли бы вы дать ссылку, объясняющую, как?
Грег
2

Вот еще один способ добиться этого:

public boolean onOptionsItemSelected(MenuItem item) {

    int id = item.getItemId();

    item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem item) {
            item.setEnabled(true);
            item.setTitle(Html.fromHtml("<font color='#ff3824'>Settings</font>"));
            return false;
            }
        });


    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

}

Абхишек
источник
Моя забота касалась того, что, если я хочу изменить цвет выбранного элемента всплывающего меню, но благодаря вам у меня появилась отличная идея из вашего этого решения по изменению цвета выбранного элемента меню ... так что вы голосуете !!! А обходной путь выглядит как :: item.setTitle (Html.fromHtml ("<font color = '# ff3824'> Настройки </font>"));
Tarit Ray 05
1

Вот как это можно сделать с помощью метода onCreate в Activity:

NavigationView navigationView = findViewById(R.id.nav_view);
ColorStateList csl = new ColorStateList(
    new int[][] {
        new int[] {-android.R.attr.state_checked}, // unchecked
        new int[] { android.R.attr.state_checked}  // checked
    },
    new int[] {
        Color.BLACK,
        Color.RED
    }
);
navigationView.setItemTextColor(csl);
navigationView.setItemIconTintList(csl);
tguen
источник
1

Шаг 1: Создайте отмеченный / непроверенный селектор:

selector.xml

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

Шаг 2: используйте атрибут xml app:itemTextColorв 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"
    app:headerLayout="@layout/navigation_header_layout"
    app:itemTextColor="@drawable/selector"
    app:menu="@menu/navigation_menu" />

Шаг 3:
По какой-то причине, когда вы NavigationViewнажимаете элемент в меню, это не рассматривается как проверка кнопки. Поэтому вам нужно вручную установить флажок для выбранного элемента и очистить ранее выбранный элемент. Используйте нижеприведенный слушатель, чтобы сделать это

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {

    int id = item.getItemId();

    // remove all colors of the items to the `unchecked` state of the selector
    removeColor(mNavigationView);

    // check the selected item to change its color set by the `checked` state of the selector
    item.setChecked(true);

    switch (item.getItemId()) {
      case R.id.dashboard:
          ...
    }

    drawerLayout.closeDrawer(GravityCompat.START);
    return true;
}

private void removeColor(NavigationView view) {
    for (int i = 0; i < view.getMenu().size(); i++) {
        MenuItem item = view.getMenu().getItem(i);
        item.setChecked(false);
    }
}

Шаг 4:
Чтобы изменить цвет значка, используйте app:iconTintатрибут в NavigationViewпунктах меню и установите тот же селектор.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/nav_account"
        android:checked="true"
        android:icon="@drawable/ic_person_black_24dp"
        android:title="My Account"
        app:iconTint="@drawable/selector" />
    <item
        android:id="@+id/nav_settings"
        android:icon="@drawable/ic_settings_black_24dp"
        android:title="Settings"
        app:iconTint="@drawable/selector" />

    <item
        android:id="@+id/nav_logout"
        android:icon="@drawable/logout"
        android:title="Log Out"
        app:iconTint="@drawable/selector" />
</menu>

Результат:

Zain
источник