Zmień kolor zaznaczonej pozycji menu w szufladzie nawigacji


104

Korzystam z nowej biblioteki Android Design Support, aby zaimplementować szufladę nawigacji w mojej aplikacji.

Nie mogę wymyślić, jak zmienić kolor wybranej pozycji!

Oto XML menu:

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

A oto plik navigationview xml, który znajduje się wewnątrz 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>

Dziękuję za pomoc!

[EDYTUJ] Spojrzałem już na rozwiązania takie jak to: Zmień kolor tła menu Androida .

Wydaje się, że to niezły hack i pomyślałem, że dzięki nowej bibliotece Design Support Library zostanie wprowadzone coś czystszego?


Odpowiedzi:


246

Cóż, możesz to osiągnąć za pomocą zasobu stanu koloru . Jeśli zauważysz, że w środku NavigationViewużywasz

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

Tutaj zamiast używać @color/blacklub @color/primary_test, użyj pliku Color State List Resource. W tym celu najpierw utwórz nowy xml(np. Drawer_item.xml) wewnątrz colorkatalogu (który powinien znajdować się w reskatalogu). Jeśli nie masz jeszcze nazwanego katalogu color, utwórz go.

Teraz w środku drawer_item.xmlzrób coś takiego

<?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>

Ostatnim krokiem byłaby zmiana 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">

Jak to można użyć oddzielnych Kolor Stan List Zasoby dla IconTint, ItemTextColor, ItemBackground.

Teraz, gdy ustawisz element jako zaznaczony (w trybie xmllub programowo), określony element będzie miał inny kolor niż elementy niezaznaczone.


Pamiętaj, że aby press działał, musisz zmienić go z android: state_checked na android: state_pressed.
Programista,

33
w przypadku elementu ItemBackground należy użyć elementu do rysowania zamiast koloru, ponieważ nie można zdefiniować tła za pomocą zasobu koloru.
sirFunkenstine

@sash, jeśli chcemy zmienić obraz ikony na wybranym elemencie nawigacyjnym, jak to zrobimy?
mohit

@sirFunkenstine Jeśli używasz selektora kolorów, możesz umieścić go w folderze kolorów w folderze res.
Kishan Vaghela,

@KishanVaghela robi to, co sugerujesz, powoduje następujący błąd: Linia pliku binarnego XML nr 3: tag <item> wymaga atrybutu „drawable” lub tagu podrzędnego definiującego element do rysowania
iOSAndroidWindowsMobileAppsDev

67

Myślę, że app:itemBackgroundoczekuje rysowalnego. Więc wykonaj poniższe czynności:

Utwórz plik do rysowania highlight_color.xmlz następującą zawartością:

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

Utwórz kolejny plik do rysowania nav_item_drawable.xmlz następującą zawartością:

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

Na koniec dodaj app:itemBackgroundtag w 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">

tutaj plik highlight_color.xml definiuje jednolity kolor, który można narysować jako tło. Później ten kolor do rysowania jest przypisany do selektora nav_item_drawable.xml.

To zadziałało dla mnie. Mam nadzieję, że to pomoże.

********************************************** AKTUALIZACJA *** *******************************************

Chociaż powyższa odpowiedź daje ci dobrą kontrolę nad niektórymi właściwościami, ale sposób, w jaki mam zamiar opisać, wydaje się bardziej SOLIDNY i nieco chłodniejszy .

Możesz więc zdefiniować ThemeOverlay w styles.xmlwidoku NavigationView w następujący sposób:

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

teraz zastosuj to ThemeOverlay do app:themeatrybutu NavigationView, na przykład:

<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">

Mam nadzieję, że to pomoże.


1
Ta metoda może być również używana w android:background="@drawable/nav_item_drawable"przypadku innych widżetów, takich jak RadioButton, Checkbox, Button itp. Redukuje programowanie typu bloatware do obsługi setOnCheckedChangeListenertylko podświetlania kolorów.
rupinderjeet,

@Ankush to działa, ale tekst i ikona znikają, ustawiłem też kolor odcienia przedmiotu, ale nie działa. czy możesz mi zasugerować, jak to zrobić
Użytkownik

1
@User Nie wiem, co poszło nie tak z twoim kodem, ale dodałem do odpowiedzi. Całkowicie inny sposób na osiągnięcie tego samego przy mniejszym wysiłku. Możesz to sprawdzić.
Ankush

1
Należy to przyjąć jako odpowiedź! Dziękuję bardzo, bardzo pomocny !!!
Svetlana Rozhkova

NIE ZAPOMNIJ ZASTOSOWAĆ „CHECKABLE = TRUE” W SWOIM MENU XML, ABY TŁO DZIAŁAŁ PRAWIDŁOWO
Ankit

4

Należy ustawić NavigateItemzaznaczone na true po każdym NavigateViewkliknięciu elementu

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

Dodaj NavigationItemSelectedListenernaNavigationView

  @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;
  }

Dziękuję za pomoc Vikalp, ale już to robię ( setChecked(true)). Widzę, jak zmienia się kolor zaznaczonego elementu, ale nie mogę go samodzielnie zmodyfikować, kolor jest zawsze jaśniejszą wersją tła widoku nawigacji.
Greg,

@Greg Domyślnie, setChecked(true)na Viewkolor tła zapisu do zmiany tematu, że urządzenie, którego używa. Jeśli chcesz zmienić tło elementu na inny kolor, musisz nadmuchać układ w DrawerLayoutlub NavigationViewi poradzić sobie samodzielnie.
Vikalp Patel

jeszcze raz dziękuję, próbowałem zrobić to, co mi powiedziałeś, ale bez powodzenia, czy miałbyś link wyjaśniający, jak proszę?
Greg

2

Oto inny sposób, aby to osiągnąć:

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

}


Mój dobut zastanawiał się, co zrobić, jeśli chcę zmienić kolor wybranej pozycji menu podręcznego, ale dzięki Tobie mam jeden świetny pomysł z twojego rozwiązania na zmianę koloru wybranej pozycji menu ... więc oddaję głos !!! A obejście wygląda następująco :: item.setTitle (Html.fromHtml ("<font color = '# ff3824'> Ustawienia </font>"));
Tarit Ray

1

Oto, jak możesz to zrobić w metodzie onCreate swojej aktywności:

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

1

Krok 1: Zbuduj zaznaczony / niezaznaczony selektor:

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>

Krok 2: użyj atrybutu xml app:itemTextColorw NavigationViewwidgecie, aby wybrać kolor tekstu.

<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" />

Krok 3:
Z jakiegoś powodu, gdy trafisz na element z NavigationViewmenu, nie uważa tego za sprawdzenie przycisku. Musisz więc ręcznie sprawdzić wybrany element i wyczyścić poprzednio wybrany element. Użyj poniższego listenera, aby to zrobić

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

Krok 4:
Aby zmienić kolor ikony, użyj app:iconTintatrybutu w NavigationViewpozycjach menu i ustaw ten sam selektor.

<?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>

Wynik:

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.