I have a navigation drawer, with some voices.
navigationView = (NavigationView) findViewById(R.id.navigation_view);
One of that voices has id "list_member", in position #2 (so it has id 1).
I need to get that position, to use in another part of code.
Something of this pseudocode:
if (navigationView.getMenu().item has label == "list_member") {
id_position = this.getId();
}
navigationView.getMenu().getItem(id_position).setChecked(state);
You could add a tag with setTag() to your View then iterate over the container of your navigation views and return the child position.
you can use setNavigationItemSelectedListener as like below :
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 perform appropriate action
switch (menuItem.getItemId()){
case R.id.list_member:
// Do your code here...
return true;
default:
return trToast.makeText(getApplicationContext(),"Somethings Wrong",Toast.LENGTH_SHORT).show();ue;
}
}
});
Every View has a so called tag property, I believe that would suite your need to store such info which would act as "label" in your context.
Details here: http://developer.android.com/reference/android/view/View.html#attr_android:tag
You can set this property either in the layout resource XML or programmatically by calling view.setTag(Object tag) or setTag(int key, Object tag) and then retreive it by calling view.getTag() or view.getTag(int key).
Or you can also call view.findViewWithTag(Object tag) on parent view to find a view with a specific tag in it's child views
(http://developer.android.com/reference/android/view/View.html#findViewWithTag(java.lang.Object))
in you case it would like something like this:
((Checkable) navigationView.getMenu().findViewWithTag("list_member")).setChecked(state);
hope this helps
Related
I have only one user setting in my app, and I want to put it into the navigation drawer with a switch added to the given menu item.
Here is the relevant menu code:
<item
android:id="#+id/nav_dark"
android:checkable="true"
android:icon="#drawable/round_brightness_4_24"
android:title="#string/menu_dark"
app:actionViewClass="android.widget.Switch" />
The switch does appear on the right side of the menu item.
My listener:
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
if (item.getItemId() == R.id.nav_dark) {
// code to apply dark or light theme
// works as expected
}
else {
// code to handle regular menu items
// it works too
}
return true;
}
My problems:
When I tap on R.id.nav_dark the item gets selected. I would like the colored overlay to stay on (or jump back to) the previous menu item, whose fragment is actually shown behind the drawer.
The switch does not react accordingly, even if I use item.setChecked(true) manually. I would like the switch to be turned on when the dark theme is enabled and turned off when it's disabled.
Tapping on the switch itself does not pass the event to the menu item. I would like them to work in sync.
I have seen checkboxes and swiches working like this in other applications, although, most of them were in the app bar's overflow menu. (I have tried mine with a checkbox too, but no difference.)
I solved this problem using this thread: Switch in Navigation drawer item with Design Support Library on Android
In this example the dedicated menu item switches between a light and dark theme, but you can use it to toggle any settings, of course.
Problems to solve
Implement our own onNavigationItemSelected listener, because the default solution created by Android Studio prevents the use of a dedicated menu item.
Implement the fragment transaction and toolbar handling logic.
Implement the onCheckedChange listener of the switch.
What we do is capture clicks on the menu items. If it's a regular item, we change the fragment behind the drawer. If it's the dedicated item with the switch, we manually toggle the switch, which calls its listener.
The actual code (changing the theme in this case) is handled by the listener of the switch. If you click on the switch itself, the listener will be called directly.
Relevant code from activity_main_drawer.xml menu file
<item
android:id="#+id/nav_dark"
android:checkable="true"
android:icon="#drawable/round_brightness_4_24"
android:title="#string/menu_dark"
app:actionViewClass="android.widget.Switch" /> <!-- you can also use a CheckBox -->
Relevant code from MainActivity.java
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, Switch.OnCheckedChangeListener {
private Toolbar toolbar;
private DrawerLayout drawerLayout;
private ActionBarDrawerToggle toggle;
private NavigationView navigationView;
private Switch switchDark;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = findViewById(R.id.toolbar);
toolbar.setTitle(getResources().getString(R.string.toolbar_title));
setSupportActionBar(toolbar);
// We have to handle the fragment changes manually,
// because what we do conflicts with the default solution created by Android Studio
drawerLayout = findViewById(R.id.drawer_layout);
toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawerLayout.addDrawerListener(toggle);
toggle.setDrawerIndicatorEnabled(true);
toggle.syncState();
navigationView = findViewById(R.id.nav_view);
// Check the menu item connected to the default fragment manually
navigationView.getMenu().findItem(R.id.nav_item1).setChecked(true);
navigationView.setNavigationItemSelectedListener(this); // See below!
switchDark = (Switch)navigationView.getMenu().findItem(R.id.nav_dark).getActionView();
// Set the default state of the switch connected to the menu item
switchDark.setChecked(AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES);
switchDark.setOnCheckedChangeListener(this); // See below!
}
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
// Handle the menu item with the switch
if (item.getItemId() == R.id.nav_dark) {
((Switch)item.getActionView()).toggle(); // Call the onCheckedChangeListener of the switch and let it do the work
return false; // Prevent the menu item to get selected (No overlay indicator will appear)
}
// Handle the other menu items
// We have to do this, because we deleted the default solution created by Android Studio
Fragment newFragment = null;
if (item.getItemId() == R.id.nav_item1) {
newFragment = new CustomFragment();
toolbar.setTitle(getResources().getString(R.string.custom_fragment_title));
}
else if (item.getItemId() == R.id.nav_item2) {
newFragment = new OtherFragment();
toolbar.setTitle(getResources().getString(R.string.other_fragment_title));
}
// Start the fragment transition manually
if (newFragment != null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.nav_host_fragment, newFragment);
transaction.addToBackStack(null);
transaction.commit();
drawerLayout.close();
}
return true; // The selected item will have the overlay indicator
}
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(buttonView.getContext());
SharedPreferences.Editor editor = sharedPreferences.edit();
int themeID;
if (isChecked) {
themeID = AppCompatDelegate.MODE_NIGHT_YES;
}
else {
themeID = AppCompatDelegate.MODE_NIGHT_NO;
}
AppCompatDelegate.setDefaultNightMode(themeID); // Change the theme at runtime
editor.putInt("themeID", themeID); // Save it to be remembered at next launch
editor.apply();
}
}
try this one.
<item
app:actionViewClass="androidx.appcompat.widget.SwitchCompat"
android:icon="#drawable/message"
android:title="All inboxes"
android:id="#+id/inbox"
/>
this above is the menu item we need
in order to get click events follow below steps mentioned
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
if (item.getItemId()==R.id.inbox){
((SwitchCompat) item.getActionView()).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked){
Toast.makeText(buttonView.getContext(), "Checked", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(buttonView.getContext(), "unChecked", Toast.LENGTH_SHORT).show();
}
}
});
}
Toast.makeText(MainActivity.this, ""+item.getTitle(), Toast.LENGTH_SHORT).show();
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
});
we already given our action class in menu item from xml .
we just need to verify which item it was and when it happens we can get the actionviewclass that we had assigned
and an onclicklistener on it .. this one worked for me .
In my app, I need to change the menu of the navigationView, when I click on the header
First state
Second state
I wanted to get the currently active menu of my navigationView to toggle between the two menus. This is what I have written so far:
public void toggleMenu(){
navigationView.getMenu().clear();
navigationView.inflateMenu(R.menu.menu_trips);
}
Instead of inflating the same menu all the time, I need to create an if to inflate the menu which is not currently active, something like this:
if (navigationView == R.menu.menu_trips){
navigationView.inflateMenu(R.menu.activity_main_drawer);
} else if (navigationView == R.menu.activity_main_drawer){
navigationView.inflateMenu(R.menu.menu_trips);
}
I do not want to add an MenuItem, I just want to replace the menu. Clearing it and then inflating is the best option I found.
If you have a better solution, please tell me :)
You can not get menu id from Menu class.
I suggest you to keep a global variable that keeps your current menu id. Or you can compare first items to understand which menu is currently active.
Solved it:
String activeMenu;
protected void onCreate(){
activeMenu = "main";
}
public void toggleMenu(){
navigationView.getMenu().clear();
if (activeMenu.equals("main")){
navigationView.inflateMenu(R.menu.menu_trips);
activeMenu = "trips";
} else if (activeMenu.equals("trips")){
navigationView.inflateMenu(R.menu.activity_main_drawer);
activeMenu = "main";
}
}
If I add a custom item to my NavigationView menu, like so:
Menu menu = navigationView.getMenu();
MenuItem item = menu.add("Item 1");
How can I set data to the item (like an object) so that, when it's clicked/selected, I can pass that data to the activity it opens?
You can't set/add data to menu items. By looking at the documentation of add() method, it can be seen that you can set:
groupId - int: The group identifier that this item should be part of. This can be used to define groups of items for batch state changes. Normally use NONE if an item should not be in a group.
itemId - int: Unique item ID. Use NONE if you do not need a unique ID.
order - int: The order for the item. Use NONE if you do not care about the order. See getOrder().
title - CharSequence: The text to display for the item.
Therefore:
You need to set itemId and handle specific tasks inside onNavigationItemSelected()
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.id_of_menu_item_1) {
// handle intents and passing data
} else if (id == R.id.id_of_menu_item_2) {
// handle intents and passing data
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
This doesn't make sense for me. MenuItem class only holds attributes relative to menu item. You cannot put other objects inside MenuItem instance. Take a look about MenuItem class:
MenuItem class
You can use repository pattern to get needed data on new activity or load object on current activity and pass to new activity using intent, just create a Bundle and put your serializable or parcelable object on it. You can make this when you handle onNavigationItemSelected(MenuItem item)
When I created a new project I used Navigation Drawer Activity
app screen
Now each menu item when I click on it will open a fragment by calling a method name replacement.
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_home) {
replaceFragment(0);
setTit = "Your State Info.";
setTitle(setTit);
} else if (id == R.id.nav_flashcards) {
replaceFragment(1);
setTit = "Flash Cards";
setTitle(setTit);
in fragment 1 I have a RadioGroup when the checked change will open the fragmet depends on the radio checked.
#Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
RadioButton radioButton = (RadioButton)getActivity().findViewById(i);
if(radioButton.getTag()==1)
((MainActivity) getActivity()).replaceFragment(0);
else if ((radioButton.getTag()==2))
((MainActivity) getActivity()).replaceFragment(2);
}
The App work fine , but the issue is how can I change the Navigation Item Selected and also change the title for the action bar.
it's possible to use this way
((MainActivity) getActivity()).onNavigationItemSelected(menuitem);
but from the fragment how can I access the the items in the menu>activity_main_drawer.xml and pass it through menuitem
This works for me..
NavigationView navigationView = (NavigationView) getActivity().findViewById(R.id.nav_view);
navigationView.getMenu().getItem(2).setChecked(true);
In your fragment you have to add setOptionsMenu(true)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// TODO Add your menu entries here
super.onCreateOptionsMenu(menu, inflater);
}
question is not clear.
whole point of navigation drawer with fragments is to access navigation and its main toolbar all over the fragments with a single main activity.(the blue color one in your image, you should be able to change this anytime when you load a fragment)
But you need to make the frame/parent view of the fragments blow the tool bar view(that's why normally it comes with two XMLs, activtyMain.xml and contentMain.xml where content main is included below the tool bar in activityMain.XML) so you create fragments view match_parent to this contentMain.xml ,you can see toolbar is accessible to the each and every fragment you add in that view because its in the main activity where fragment/s add.
so you have a main activity and inside that you have fragment/s frame. Doesn't matter what fragment you load you can still have the access to main toolbar.
so once you check which item got clicked in navigationDrawer you load the fragment related to that right?. and there access the main toolbar of the mainActivity and do the changes that you need to display.That's it!
if (id == R.id.nav_whatever) {
// access toolBar or any view in main activity and do the changes
// call relevant fragment
}
But you cannot access that toolbar or mainActivity views inside your Fragment class that you try to attempt.
Edit :
Keep a Boolean in a Constant class or something similar,
then when you click on your button on second fragment change the value .
Now let's say Boolean is true
Then you click the navigation drawer again
// keep the id as it is and use the Boolean to check where you needs to go
if (id == R.id.nav_whatever) {
if(boolianName){
// boolianName is true go load second fragment
}else{
// load firstfragment
}
}
If you use Navegation drawer, you can use this code, put it on onCreate method:
NavigationView navigationView = (NavigationView) getActivity().findViewById(R.id.nav_view);
navigationView.getMenu().getItem(2).setChecked(true);
Several tries to ask this question in #android-dev (irc) and hours of searching, but I still don't have a solution to this problem.
I'm currently working on the search-function in my android music player. I'm using the amazing ActionBarSherlock to provide support for older android versions.
My Problem is the following:
When the user clicks the search menu/action button, the actionView of the clicked action should be expanded, and a new Fragment (the searchFragment) should be shown instead of the currently active one.
However when i'm attempting to do this, the actionView doesn't expand.
I've tried to expand the actionView, without adding the SearchFragment, and in that case the actionView DOES expand. However the combination seems impossible.
Here's my code:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item != null) {
if (item.getItemId() == R.id.collectionactivity_search_menu_button) {
item.expandActionView();
mTabsAdapter.replace(new SearchFragment(), false);
return true;
}
}
return false;
}
/**
* Replaces the view pager fragment at specified position.
*/
public void replace(int position, Fragment newFragment, boolean isBackAction) {
// Get currently active fragment.
ArrayList<Fragment> fragmentsStack = mFragments.get(position);
Fragment currentFragment = fragmentsStack.get(fragmentsStack.size() - 1);
if (currentFragment == null) {
return;
}
// Replace the fragment using a transaction.
this.startUpdate(mViewPager);
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.attach(newFragment).remove(currentFragment).commit();
if (isBackAction == true)
fragmentsStack.remove(currentFragment);
else
fragmentsStack.add(newFragment);
this.notifyDataSetChanged();
this.finishUpdate(mViewPager);
}
The mTabsAdapter.replace(...) method replaces the currently shown Fragment with the one in the first parameter. In Addition the fragment is being added to a custom backStack.
Replacing the Fragment before or after expanding the View didn't make any difference.
Hopefully somebody is able to help me :)
thanks in advance!
Have you tried setting your actionviews android:showAsAction to collapseActionView? that way you don't have to manage the expand/close action.
If that does not work you can handle it in another way,you set an expand listener and replace your fragment once your action view starts expanding
item.setOnActionExpandListener(new OnActionExpandListener() {
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
// Do something when collapsed
return true; // Return true to collapse action view
}
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
mTabsAdapter.replace(new SearchFragment(), false);
return true; // Return true to expand action view
}
});
remember to return true to let the actionview expand
I found out what the problem was caused by.
My mTabsAdapter.replace(..) method was calling notifyDataSetChanged();. So everytime I replaced the fragment, onPrepareOptionsMenu was being called, resulting in the search action button being removed and added again, thus resulting in the actionView being collapsed.
The solution to this is to fix my onPrepareOptionsMenu, so the actionView will be expanded again, whenever onPrepareOptionsMenu is called and the actionView was expanded before.