I'm trying to change the text color of the selected item in the NavigationView. Using the information for the previous topic I set a selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/primaryColor" android:state_checked="true" />
<item android:color="#color/lightGrayColor" android:state_checked="false" />
</selector>
The primaryColor is blue. The NavigationView is as follows:
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/activity_nav_header"
app:menu="#menu/nev_menu"
app:itemIconTint="#drawable/menu_item_selector"
app:itemTextColor="#drawable/menu_item_selector" />
</androidx.drawerlayout.widget.DrawerLayout>
As you can see I set app:itemTextColor to menu_item_selector. But when I run the application, I see the selected item as grey. How does the NavigationView know which screen am I seeing right now? How do I fix it?
I'm using onNavigationItemSelected to switch between activities. Also I currently have only two windows - the dashboard and the logout. From the main screen I move to the dashboard (which contains the menu) and using the logout I go back to the main screen. Maybe the reason for it not working is because it does not know that the current screen is dashboard?
The dashboard java cotnains the following method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dashboard);
toolBar = findViewById(R.id.toolbar);
setSupportActionBar(toolBar);
drawerLayout = findViewById(R.id.drawer_layout);
navigationView = findViewById(R.id.nav_view);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawerLayout, toolBar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawerLayout.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
View hView = navigationView.getHeaderView(0);
}
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.dashboard:
// CURRENT ACTIVITY
break;
case R.id.messages:
startActivity(new Intent(this, MessagesActivity.class));
break;
case R.id.settings:
startActivity(new Intent(this, SettingsActivity.class));
break;
case R.id.about:
startActivity(new Intent(this, AboutActivity.class));
break;
case R.id.logout:
startActivity(new Intent(this, MainActivity.class));
break;
}
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
For the initial look, you set a checked color to primaryColor, but overwrite it with lightGrayColor as you didn't specify the state that this color is available at; so you need to specify the state by android:state_checked="false"
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/primaryColor" android:state_checked="true" />
<item android:color="#color/lightGrayColor" android:state_checked="false"/>
</selector>
You can also set the default selected item at the app start by trying any of:
navigationView.getMenu().getItem(0).setChecked(true);
navigationView.setCheckedItem(R.id.nav_item);
Update
This is how it works with me
Step 1: Use the same selector:
selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/primaryColor" android:state_checked="true" />
<item android:color="#color/lightGrayColor" android:state_checked="false" />
</selector>
Step 2: use the xml attribute app:itemTextColor within NavigationView widget
<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" />
Step 3:
The previous step attribute won't work automatically as for some reason when you hit an item from the NavigationView menu, it doesn't consider this as a button check. So you need to manually get the selected item checked and clear the previously selected item. Use below listener to do that
#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:
// CURRENT ACTIVITY
break;
case R.id.messages:
startActivity(new Intent(this, MessagesActivity.class));
break;
case R.id.settings:
startActivity(new Intent(this, SettingsActivity.class));
break;
case R.id.about:
startActivity(new Intent(this, AboutActivity.class));
break;
case R.id.logout:
startActivity(new Intent(this, MainActivity.class));
break;
}
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);
}
}
Now the text color will change perfectly.
Step 4:
To change icon colors, use the app:iconTint attribute in the NavigationView menu items, and set to the same selector.
<?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>
Result:
Related
For some reason, in my bottom navigation bar, my second item doesn't work
But the first one does, I can't figure out why.
when I press the navigation_building button , I don't reach the corresponding case.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/navigation_home"
android:title="•"
android:enabled="true"
android:icon="#drawable/ic_home_black_18dp"/>
<item
android:id="#+id/navigation_building"
android:title="•"
android:enabled="true"
android:icon="#drawable/ic_domain_black_18dp"/>
<item
android:id="#+id/navigation_transfert"
android:title="•"
android:enabled="true"
android:icon="#drawable/ic_import_export_black_18dp"/>
<item
android:id="#+id/navigation_settings"
android:title="•"
android:enabled="true"
android:icon="#drawable/ic_settings_black_18dp"/>
</menu>
bottomNavigationView.setOnNavigationItemReselectedListener(new BottomNavigationView.OnNavigationItemReselectedListener() {
#Override
public void onNavigationItemReselected(#NonNull MenuItem item) {
Toolbar toolbar = findViewById(R.id.toolbar);
// Handle navigation view item clicks here.
switch (item.getItemId()) {
case R.id.action_logout: {
finish();
}
case R.id.navigation_home: {
loadFragment(new HomeFragment());
break;
}
case R.id.navigation_building: {
loadFragment(new BuildingFragment());
break;
}
}
You are setting NavigationItemReselectedListener. This is only triggered when the current selected navigation item is reselected. You are probably looking for NavigationItemSelectedListener.
I was working on Nav drawer on my app.
I have made the background of my nav drawer #000000(Black). Whenever I select any item the textcolor of text changes from #E44F50(Carrot Red) to black but I cant change the background color of the selected item.
All I want is to change the background color of selected Item from black to carrot red.
Here is the github link to my app-
https://github.com/manmeet-22/NewsSnips-app.git
<android.support.design.widget.NavigationView
android:id="#+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#color/colorPrimary"
app:headerLayout="#layout/header"
app:itemIconTint="#drawable/drawer_item" //changing text color
app:itemTextAppearance="#style/TextAppearance20"
app:itemTextColor="#color/drawer_item"
app:itemBackground="#drawable/drawer_selected_item" //trying to change backgroundcolor the same way
app:menu="#menu/drawer"
tools:context="com.androidexample.newssnips.app.NavigationDrawerFragment"/>
</android.support.v4.widget.DrawerLayout>
In this I tried changing the background color like I did for the text but my app crashes.
here is my drawer_selected_item.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/colorAccent" android:state_selected="true"/>
<item android:color="#android:color/transparent"/>
</selector>
here is my drawer_item.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/colorPrimary" android:state_checked="true" />
<item android:color="#color/colorAccent" />
</selector>
Here is my MainActivity.java:
navigationView = (NavigationView) findViewById(R.id.navigation_view);
navigationView.setItemIconTintList(null);
Menu menu = navigationView.getMenu();
//For chnaging the textColor and textSize of group's Name ie. Category
MenuItem categoryName= menu.findItem(R.id.categoryGroup);
SpannableString s = new SpannableString(categoryName.getTitle());
s.setSpan(new TextAppearanceSpan(this, R.style.TextAppearance25), 0, s.length(), 0);
//For changing the Text of action bar as the selected category
categoryName.setTitle(s);
//Setting Navigation View Item Selected Listener to handle the item click of the navigation menu
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
// This method will trigger on item Click of navigation menu
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
//Checking if the item is in checked state or not, if not make it in checked state
if (menuItem.isChecked())
menuItem.setChecked(false);
else
menuItem.setChecked(true);
//Closing drawer on item click
drawerLayout.closeDrawers();
//Check to see which item was being clicked and open the Appopriate news accordingly
switch (menuItem.getItemId()) {
case R.id.itemWorld:
GAURDIAN_REQUEST_URL = "http://content.guardianapis.com/search?api-key=f51fa87d-8a55-4fc1-b552-8fa6eb98dee4§ion=world";
setTitle("World News");
basicDefaults();
return true;
case R.id.itemFootball:
GAURDIAN_REQUEST_URL = "http://content.guardianapis.com/search?api-key=f51fa87d-8a55-4fc1-b552-8fa6eb98dee4§ion=football";
setTitle("Football News");
basicDefaults();
return true;
case R.id.itemFashion:
GAURDIAN_REQUEST_URL = "http://content.guardianapis.com/search?api-key=f51fa87d-8a55-4fc1-b552-8fa6eb98dee4§ion=fashion";
setTitle("Fashion News");
basicDefaults();
return true;
case R.id.itemSports:
GAURDIAN_REQUEST_URL = "http://content.guardianapis.com/search?api-key=f51fa87d-8a55-4fc1-b552-8fa6eb98dee4§ion=sport";
setTitle("Sports News");
basicDefaults();
return true;
case R.id.itemBusiness:
GAURDIAN_REQUEST_URL = "http://content.guardianapis.com/search?api-key=f51fa87d-8a55-4fc1-b552-8fa6eb98dee4§ion=business";
setTitle("Business News");
basicDefaults();
return true;
case R.id.itemTechnology:
GAURDIAN_REQUEST_URL = "http://content.guardianapis.com/search?api-key=f51fa87d-8a55-4fc1-b552-8fa6eb98dee4§ion=technology";
setTitle("Technology News");
basicDefaults();
return true;
case R.id.itemOpinion:
GAURDIAN_REQUEST_URL = "http://content.guardianapis.com/search?api-key=f51fa87d-8a55-4fc1-b552-8fa6eb98dee4§ion=commentisfree";
setTitle("Opinions");
basicDefaults();
return true;
case R.id.itemCulture:
GAURDIAN_REQUEST_URL = "http://content.guardianapis.com/search?api-key=f51fa87d-8a55-4fc1-b552-8fa6eb98dee4§ion=culture";
setTitle("Culture News");
basicDefaults();
return true;
case R.id.itemTravel:
GAURDIAN_REQUEST_URL = "http://content.guardianapis.com/search?api-key=f51fa87d-8a55-4fc1-b552-8fa6eb98dee4§ion=travel";
setTitle("Travel News");
basicDefaults();
return true;
case R.id.itemLifestyle:
GAURDIAN_REQUEST_URL = "http://content.guardianapis.com/search?api-key=f51fa87d-8a55-4fc1-b552-8fa6eb98dee4§ion=lifeandstyle";
setTitle("LifeStyle News");
basicDefaults();
return true;
case R.id.itemEnvironment:
GAURDIAN_REQUEST_URL = "http://content.guardianapis.com/search?api-key=f51fa87d-8a55-4fc1-b552-8fa6eb98dee4§ion=environment";
setTitle("Environment News");
basicDefaults();
return true;
default:
Toast.makeText(getApplicationContext(), "Somethings Wrong", Toast.LENGTH_SHORT).show();
return true;
}
}
});
// Initializing Drawer Layout and ActionBarToggle
drawerLayout = (DrawerLayout) findViewById(R.id.drawer);
ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.openDrawer, R.string.closeDrawer) {
#Override
public void onDrawerClosed(View drawerView) {
// Code here will be triggered once the drawer closes as we dont want anything to happen so we leave this blank
super.onDrawerClosed(drawerView);
}
#Override
public void onDrawerOpened(View drawerView) {
// Code here will be triggered once the drawer open as we dont want anything to happen so we leave this blank
super.onDrawerOpened(drawerView);
}
};
//calling sync state is necessay or else your hamburger icon wont show up
actionBarDrawerToggle.syncState();
}
PS.- I have tried implementing other methods too like
adding this in apptheme in styles.xml file.
<item name="android:activatedBackgroundIndicator">#drawable/drawer_selected_item</item>
But still I cant find my solution.
Please help it is the last thing that is left in my project.
I have got the solution-
In the NavigationView I did-
app:itemBackground="#drawable/drawer_selected_item"
Thus my NavigationView looks like-
<android.support.design.widget.NavigationView
android:id="#+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#color/colorPrimary"
app:headerLayout="#layout/header"
app:itemIconTint="#drawable/drawer_item"
app:itemTextAppearance="#style/TextAppearance20"
app:itemTextColor="#drawable/drawer_item"
app:menu="#menu/drawer"
app:itemBackground="#drawable/drawer_selected_item"
tools:context="com.androidexample.newssnips.app.NavigationDrawerFragment" />
In the drawer_selected_item I modified file as-
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="#color/colorAccent"/>
<item android:drawable="#android:color/transparent" />
</selector>
NavigationView has a method called setItemTextColor(). It uses a ColorStateList.navigationView.setItemTextColor(). with ColorStateList as a parameter.
Adding explanation to Caspian's answer:
Android Developers Documentation provides ColorStateList so you can play around on different states of a View in android.
Example Code here: ColorStateList Android Example
I have a drawer layout that needs to have two navigation views in it, because there's a couple of options that need to be aligned on top and another on the bottom, with a divider separating them.
I've managed to make it work, but now I have two different problems with my setup.
1) The first one, I can't change the selected items text color (the background color works as intented via a drawer selector, but for some reason, the selected item's text color is always colorPrimary)
2) The second one is trickier, since there's two navigation views, it can happen that there's a selected row on the first and on the second one, even though they all work loading fragments in the same container. Is there a way to manage that, when an item for the first navigation view is selected, the second navigation view's selected item gets deselected?
This is the drawer's layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- 1º Layout de la activity -->
<include layout="#layout/activity_main"/>
<!-- 2º Layout del drawer -->
<android.support.design.widget.NavigationView
android:id="#+id/container_navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:itemBackground="#drawable/drawer_list_selector"
android:nestedScrollingEnabled="true"
android:scrollIndicators="none">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:layout_width="match_parent"
android:layout_height="#dimen/divider_height"
android:background="#color/colorAccent"
android:layout_above="#+id/navigation_view"
android:id="#+id/top_separator"/>
<android.support.design.widget.NavigationView
android:id="#+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:layout_above="#+id/bottom_separator"
app:itemBackground="#drawable/drawer_list_selector"
app:menu="#menu/menu_navigation" />
<View
android:layout_width="match_parent"
android:layout_height="#dimen/divider_height"
android:background="#color/colorAccent"
android:layout_above="#+id/navigation_bottom"
android:id="#+id/bottom_separator"/>
<android.support.design.widget.NavigationView
android:id="#+id/navigation_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:menu="#menu/menu_navigation_bottom"
app:itemBackground="#drawable/drawer_list_selector"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
This is the top navigation view's layout:
<?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">
<group android:checkableBehavior="single">
<item
android:id="#+id/nav_tus_ofertas"
android:title="#string/tus_ofertas"
android:icon="#drawable/ic_offer" />
<item
android:id="#+id/nav_movimiento_puntos"
android:title="#string/movimiento_puntos"
android:icon="#drawable/ic_points"/>
<item
android:id="#+id/nav_asociaciones"
android:title="#string/asociaciones"
android:icon="#drawable/ic_flag"/>
</group>
</menu>
Bottom navigation view's layout:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="#+id/nav_terminos"
android:title="#string/terminos"
android:icon="#drawable/ic_document" />
<item
android:id="#+id/nav_contacto"
android:title="#string/contacto"
android:icon="#drawable/ic_email"/>
<item
android:id="#+id/nav_valorar"
android:title="#string/valorar"
android:icon="#drawable/ic_rate_review"/>
<item
android:id="#+id/nav_exit"
android:title="#string/exit"
android:icon="#drawable/ic_shutdown"/>
</group>
</menu>
Selected item's background selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="#color/colorAccent" />
<item android:state_activated="true" android:drawable="#color/colorAccent" />
<item android:state_selected="true" android:drawable="#color/colorAccent" />
<item android:state_checked="true" android:drawable="#color/colorAccent" />
<item android:state_pressed="false" android:drawable="#android:color/transparent" />
<item android:state_activated="false" android:drawable="#android:color/transparent" />
<item android:state_selected="false" android:drawable="#android:color/transparent" />
<item android:state_checked="false" android:drawable="#android:color/transparent" />
</selector>
The activity that calls the drawer and handles the events:
public class MainActivity extends AppCompatActivity {
#Bind(R.id.toolbar) Toolbar toolbar;
#Bind(R.id.tabs) TabLayout tabs;
#Bind(R.id.drawer_layout) DrawerLayout drawerLayout;
#Bind(R.id.container_navigation) NavigationView containerNavigator;
#Bind(R.id.navigation_view) NavigationView navigationView;
#Bind(R.id.navigation_bottom) NavigationView navigationBottom;
#Bind(R.id.vsFooter) ViewStubCompat stub;
ImageView userPicture;
TextView userMail;
ViewPager viewPager;
Menu menu;
ActionBar actionBar;
ViewPagerFragment viewPagerFragment;
Usuario currentUser;
public Usuario getCurrentUser() {
return currentUser;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawer);
ButterKnife.bind(this);
currentUser = UserApiManager.getInstance(getApplicationContext()).getCurrentUser();
viewPagerFragment = ViewPagerFragment.newInstance();
setupToolbar();
setupNavigationDrawer();
ApiManager.getInstance(getApplicationContext()).setupFooter(stub, currentUser.getIdLocalidad(), this);
getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout,viewPagerFragment).commit();
}
public void setupViewPager(ViewPager viewPager) {
tabs.setupWithViewPager(viewPager);
}
private void setupToolbar() {
setSupportActionBar(toolbar);
actionBar = getSupportActionBar();
if (actionBar!=null){
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.ic_menu_black);
actionBar.setTitle(getString(R.string.app_title));
}
}
private void setupNavigationDrawer() {
View headerView = navigationView.inflateHeaderView(R.layout.navigation_header);
userPicture = (ImageView) headerView.findViewById(R.id.user_picture);
userMail = (TextView) headerView.findViewById(R.id.user_mail);
userMail.setText(currentUser.getEmail());
Picasso.with(this).load(currentUser.getImagenURL()).transform(new CircleTransformation()).into(userPicture);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.nav_tus_ofertas:
showTabLayout();
actionBar.setTitle(getString(R.string.app_title));
getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout,viewPagerFragment).commit();
break;
case R.id.nav_movimiento_puntos:
hideTabLayout();
Bundle bundle = new Bundle();
bundle.putString("idcliente", currentUser.getId());
MovimientoPuntosFragment movimientoPuntosFragment = MovimientoPuntosFragment.newInstance();
movimientoPuntosFragment.setArguments(bundle);
actionBar.setTitle(getString(R.string.movimiento_puntos));
getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout, movimientoPuntosFragment).commit();
break;
case R.id.nav_asociaciones:
hideTabLayout();
actionBar.setTitle(getString(R.string.asociaciones));
getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout, AsociacionFragment.newInstance()).commit();
break;
}
drawerLayout.closeDrawers();
return true;
}
});
navigationBottom.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.nav_terminos:
hideTabLayout();
actionBar.setTitle(getString(R.string.terminos));
getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout, LegalesFragment.newInstance()).commit();
break;
case R.id.nav_contacto:
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri data = Uri.parse("mailto:?subject=" + getString(R.string.contacto_email));
intent.setData(data);
startActivity(intent);
break;
case R.id.nav_valorar:
final String appPackageName = BuildConfig.APPLICATION_ID;
try {
Log.i("url", "market://details?id=" + appPackageName);
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + appPackageName)));
} catch (android.content.ActivityNotFoundException anfe) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + appPackageName)));
}
break;
case R.id.nav_exit:
break;
}
drawerLayout.closeDrawers();
return true;
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_over, menu);
this.menu = menu;
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
drawerLayout.openDrawer(GravityCompat.START);
break;
case R.id.action_user:
Intent intent = new Intent(this, PerfilUsuarioActivity.class);
startActivity(intent);
break;
}
return super.onOptionsItemSelected(item);
}
public void hideTabLayout(){
tabs.setVisibility(View.GONE);
}
public void showTabLayout(){
tabs.setVisibility(View.VISIBLE);
}
}
Any help would be appreciated!
Thanks in advance!
Solved!
The problem with the color I solved it with a selector, it didn't work before because I had a syntax error (selector tag inside the main selector tag).
This is the color selector's code:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#FFFFFFFF" android:state_checked="true" />
<item android:color="#E6000000" android:state_checked="false"/>
</selector>
The second problem I solved it by programmatically deselecting the other navigationview's items onNavigationItemSelected.
This is the function I call:
public void deselectItems(NavigationView view){
int size = view.getMenu().size();
for (int i = 0; i < size; i++) {
view.getMenu().getItem(i).setChecked(false);
}
}
I know there must be a better way to solve the second problem, but this one worked.
I'm trying to use the NavigationView in one of my projects to implement a side menu. The app has two type of users: Admin and User.
I created the login activity and I log in as user or admin. I pass the name, email via intent (putExtra) to my NavigationActivity.
Since I have two type of users I created two type of menus (admin has more menu options).
I check the content of the passed value from the intent and inflate the navigation views menu accordingly.
My problem is I don't know how to separate in the listener the two type of menus. Should I create in my if else two listeners for each case? What would be the right approach? The way I did it doesn't work correctly, in my side menu I have the first two items from the user menu and after that the reamining items of the admin menu.
Here's thecode:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_navigation);
Bundle extras = getIntent().getExtras();
String name = extras.getString("name");
String email = extras.getString("email");
toolbar = (Toolbar) findViewById(R.id.tool_bar);
setSupportActionBar(toolbar);
navigationView = (NavigationView) findViewById(R.id.navigation_view);
if(name.equals("admin")){
// listener for admin here?
navigationView.inflateMenu(R.menu.admin_drawer);
}else{
// listener for user here?
navigationView.inflateMenu(R.menu.user_drawer);
}
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
// questionable part here, doesn't work correctly
#Override
public boolean onNavigationItemSelected(MenuItem item) {
if(item.isChecked())
item.setChecked(false);
drawerLayout.closeDrawers();
switch (item.getItemId()){
// this is for user
case R.id.test:
Toast.makeText(getApplicationContext(), "Test Selected", Toast.LENGTH_SHORT).show();
TestFragment testFragment = new TestFragment();
android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frameholder, testFragment);
fragmentTransaction.commit();
return true;
// this is for user
case R.id.practice:
Toast.makeText(getApplicationContext(),"Practice Selected",Toast.LENGTH_SHORT).show();
break;
// this is for admin
case R.id.existing_questions:
Toast.makeText(getApplicationContext(),"Questions Selected",Toast.LENGTH_SHORT).show();
break;
// this is for admin
case R.id.new_questions:
Toast.makeText(getApplicationContext(),"New questions Selected",Toast.LENGTH_SHORT).show();
break;
// this is for admin
case R.id.settings:
Toast.makeText(getApplicationContext(),"Settings Selected",Toast.LENGTH_SHORT).show();
break;
// this is for admin
case R.id.users_data:
Toast.makeText(getApplicationContext(),"User data Selected",Toast.LENGTH_SHORT).show();
break;
}
return true;
}
});
Edit:
Here you have the two menus I use:
admin_drawer.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="#+id/existing_questions"
android:checked="false"
android:icon="#drawable/ic_existq"
android:title="Questions" />
<item
android:id="#+id/new_questions"
android:checked="false"
android:icon="#drawable/ic_addq"
android:title="Add question" />
<item
android:id="#+id/settings"
android:checked="false"
android:icon="#drawable/ic_settings"
android:title="Settings" />
<item
android:id="#+id/users_data"
android:checked="false"
android:icon="#drawable/ic_statistics"
android:title="Statistics" />
</group>
</menu>
user_drawer.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="#+id/test"
android:checked="false"
android:icon="#drawable/ic_test"
android:title="Test" />
<item
android:id="#+id/practice"
android:checked="false"
android:icon="#drawable/ic_practice"
android:title="Practice" />
</group>
</menu>
A good approach would be to use two groups with different IDs in the same menu. Then you can switch between them easly with .setGroupVisible() like this:
if(name.equals("admin")){
navigationView.menu.setGroupVisible(R.id.menu_group_admin, true);
navigationView.menu.setGroupVisible(R.id.menu_group_user, false);
}
else{
navigationView.menu.setGroupVisible(R.id.menu_group_admin, false);
navigationView.menu.setGroupVisible(R.id.menu_group_user, true);
}
This works seamlessly
Thanks cylon. The mistake was made by me. I inflated the navigation view in the xml, and then from code to.
I am using the new Android Design Support library to implement a navigation drawer in my application.
I can't figure out how to change the color of a selected item!
Here is the xml of the 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>
And here is the navigationview xml which is placed inside a 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>
Thank you for your help !
[EDIT]
I have already looked at solutions such as this one : Change background color of android menu.
It seems to be quite a hack and I thought that with the new Design Support Library, something cleaner would have been introduced?
Well you can achieve this using Color State Resource. If you notice inside your NavigationView you're using
app:itemIconTint="#color/black"
app:itemTextColor="#color/primary_text"
Here instead of using #color/black or #color/primary_test, use a Color State List Resource. For that, first create a new xml (e.g drawer_item.xml) inside color directory (which should be inside res directory.) If you don't have a directory named color already, create one.
Now inside drawer_item.xml do something like this
<?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>
Final step would be to change your 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">
Like this you can use separate Color State List Resources for IconTint, ItemTextColor, ItemBackground.
Now when you set an item as checked (either in xml or programmatically), the particular item will have different color than the unchecked ones.
I believe app:itemBackground expects a drawable. So follow the steps below :
Make a drawable file highlight_color.xml with following contents :
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="YOUR HIGHLIGHT COLOR"/>
</shape>
Make another drawable file nav_item_drawable.xml with following contents:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/highlight_color" android:state_checked="true"/>
</selector>
Finally add app:itemBackground tag in the 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">
here the highlight_color.xml file defines a solid color drawable for the background. Later this color drawable is assigned to nav_item_drawable.xml selector.
This worked for me. Hopefully this will help.
********************************************** UPDATED **********************************************
Though the above mentioned answer gives you fine control over some properties, but the way I am about to describe feels more SOLID and is a bit COOLER.
So what you can do is, you can define a ThemeOverlay in the styles.xml for the NavigationView like this :
<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>
now apply this ThemeOverlay to app:theme attribute of NavigationView, like this:
<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">
I hope this will help.
One need to set NavigateItem checked true whenever item in NavigateView is clicked
//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);
Add NavigationItemSelectedListener on 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;
}
Step 1: Build a checked/unchecked selector:
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>
Step 2: use the XML attribute app:itemTextColor within NavigationView widget for selecting the text color.
<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" />
Step 3 & 4:
Step 3: To make menu icons check-able: wrap all items in a <group> and setandroid:checkableBehavior="single"
Step 4: To change icon color: set the selector to all the items with app:iconTint
<?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">
<group android:checkableBehavior="single">
<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" />
</group>
</menu>
Step 5:: make sure that onNavigationItemSelected() callback returns true to consume selection event
navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
});
Result:
Side Note:
If setting android:checkableBehavior="single" not working, then you handle this programmatically by manually making the selected item checked and clear the previously selected item:
#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);
}
}
Here is the another way to achive this:
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);
}
}
Here's how you can do it in your Activity's onCreate method:
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);
if you want to keep the fillet of selected item in material 3, use app:itemShapeFillColor="#color/main_navigation_view" instead of app:itemBackground="#color/main_navigation_view"