Muda a cor de um item de menu marcado em uma gaveta de navegação

103

Estou usando a nova biblioteca Android Design Support para implementar uma gaveta de navegação em meu aplicativo.

Não consigo descobrir como mudar a cor de um item selecionado!

Aqui está o xml do 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>

E aqui está o xml de navegação, que é colocado dentro de um 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>

Obrigado pela ajuda !

[EDIT] Já observei soluções como esta: Alterar a cor de fundo do menu do Android .

Parece ser um hack e tanto, e pensei que, com a nova Biblioteca de Suporte a Design, algo mais limpo teria sido introduzido.

Greg
fonte
possível duplicata de Alterar cor de fundo do menu do Android
jlopez

Respostas:

244

Bem, você pode conseguir isso usando Color State Resource . Se você perceber NavigationViewque está usando

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

Aqui, em vez de usar @color/blackou @color/primary_test, use a Color State List Resource. Para isso, primeiro crie um novo xml(por exemplo, drawer_item.xml) dentro do colordiretório (que deve estar dentro do resdiretório.) Se você ainda não tiver um diretório chamado color, crie um.

Agora dentro drawer_item.xmlfaça algo assim

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

A etapa final seria mudar seu 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">

Assim você pode usar separadas Cor Estado Listar recursos para IconTint, ItemTextColor, ItemBackground.

Agora, quando você define um item como marcado (tanto em xmlou programaticamente), o item particular terá uma cor diferente dos desmarcados.

Sash_KP
fonte
Lembre-se que para que funcione, você precisa alterá-lo de android: state_checked para android: state_pressed.
Programista
32
para ItemBackground, você precisa usar um drawable em vez de cor porque não pode definir um plano de fundo usando um recurso de cor.
sirFunkenstine
@sash se quisermos mudar a imagem do ícone no item de navegação selecionado, como faremos isso?
mohit
@sirFunkenstine Se você estiver usando o seletor de cores, você pode colocá-lo na pasta de cores em sua pasta res.
Kishan Vaghela
@KishanVaghela fazer o que você sugere produz este erro: Arquivo XML binário linha # 3: a tag <item> requer um atributo 'drawable' ou tag filha definindo um drawable
iOSAndroidWindowsMobileAppsDev
66

Acredito que app:itemBackgroundespera um drawable. Portanto, siga as etapas abaixo:

Faça um arquivo drawable highlight_color.xmlcom o seguinte conteúdo:

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

Faça outro arquivo drawable nav_item_drawable.xmlcom o seguinte conteúdo:

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

Por fim, adicione a app:itemBackgroundtag no 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">

aqui, o arquivo highlight_color.xml define um drawable de cor sólida para o fundo. Posteriormente, este drawable de cores é atribuído ao seletor nav_item_drawable.xml.

Isso funcionou para mim. Espero que isso ajude.

************************************************ ATUALIZADO *** ********************************************

Embora a resposta mencionada acima dê a você um controle preciso sobre algumas propriedades, a maneira que estou prestes a descrever parece mais SÓLIDA e um pouco MAIS FRESCA .

Então, o que você pode fazer é definir um ThemeOverlay no styles.xmlpara o NavigationView assim:

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

agora aplique este ThemeOverlay ao app:themeatributo de NavigationView, como este:

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

Espero que isso ajude.

Ankush
fonte
1
Além disso, este método pode ser usado como android:background="@drawable/nav_item_drawable"para outros widgets como RadioButton, Checkbox, Button etc. Reduz a programação de bloatware para manipulação setOnCheckedChangeListenerapenas para realce de cores.
rupinderjeet
@Ankush isso funciona, mas o texto e o ícone desaparecem, eu configurei a cor da tonalidade do item também, mas não está funcionando. você pode me sugerir como isso pode ser feito
Usuário
1
@User Não sei o que deu errado com seu código, mas acrescentei a resposta. Uma maneira totalmente diferente de conseguir a mesma coisa com menos esforço. Você pode verificar isso.
Ankush
1
Isso deve ser aceito como uma resposta! Muito obrigado, muito útil !!!
Svetlana Rozhkova
4

É necessário definir NavigateItemverdadeiro verificado sempre que o item NavigateViewé clicado

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

Adicionar NavigationItemSelectedListeneremNavigationView

  @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;
  }
Vikalp Patel
fonte
Obrigado pela ajuda Vikalp, mas já estou fazendo isso ( setChecked(true)). Posso ver a cor do item marcado mudando, mas não posso modificá-lo sozinho, a cor é sempre uma versão mais clara do fundo do navigatioview.
Greg
@ Greg Por padrão setChecked(true)no Viewmuda de cor de fundo até tema que dispositivo que você usa. Se você quiser alterar o plano de fundo do item para alguma outra cor, precisará aumentar seu layout em DrawerLayoutou NavigationViewe manuseá-lo por conta própria.
Vikalp Patel
obrigado novamente, tentei fazer o que você me disse, mas sem sucesso, você teria um link explicando como, por favor?
Greg
2

Esta é a outra maneira de conseguir isso:

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

}

Abhishek
fonte
Minha pergunta foi sobre o que aconteceria se eu quisesse mudar a cor do item selecionado do menu pop-up, mas graças a você que tive uma ótima idéia dessa solução para mudar a cor do item selecionado do menu ... então, votando !!! E a solução alternativa é :: item.setTitle (Html.fromHtml ("<font color = '# ff3824'> Configurações </font>"));
Tarit Ray
1

Veja como você pode fazer isso no método onCreate de sua 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
fonte
1

Etapa 1: construir um seletor marcado / desmarcado:

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>

Etapa 2: use o atributo xml app:itemTextColordentro do NavigationViewwidget para selecionar a cor do texto.

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

Etapa 3:
por algum motivo, quando você clica em um item do NavigationViewmenu, isso não é considerado uma verificação de botão. Portanto, você precisa verificar manualmente o item selecionado e limpar o item selecionado anteriormente. Use o ouvinte abaixo para fazer isso

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

Etapa 4:
para alterar a cor do ícone, use o app:iconTintatributo nos NavigationViewitens de menu e defina para o mesmo seletor.

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

Resultado:

Zain
fonte