Reputation: 150
I'm working with the new NavigationView, trying to implement it into a DrawerLayout, and I want to save the currently selected menu item in the menu within the NavigationView. I know that I can save/restore the selected item "manually" by saving/restoring my instance state:
public class MyActivity extends AppCompatActivity {
private static String STATE_SELECTED_POSITION = "state_selected_position";
private int mCurrentSelectedPosition;
private NavigationView mNavigationView;
private FrameLayout mContentFrame;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
mContentFrame = (FrameLayout) findViewById(R.id.content_frame);
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
menuItem.setChecked(true);
switch(menuItem.getItemId()) {
case R.id.navigation_item_1:
Snackbar.make(contentFrame, "Item One", Snackbar.LENGTH_SHORT).show();
mCurrentSelectedPosition = 0;
return true;
case R.id.navigation_item_2:
Snackbar.make(contentFrame, "Item Two", Snackbar.LENGTH_SHORT).show();
mCurrentSelectedPosition = 1;
return true;
default:
return false;
}
}
});
}
// Saving the currently selected menu item (index).
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
}
// Restoring selected menu item.
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION, 0);
mNavigationView.getMenu().getItem(mCurrentSelectedPosition).setChecked(true);
}
}
I stumbled upon the NavigationView.SavedState, hoping this would be a better solution, but I'm having trouble figuring out how to implement this into my activity. Anyone who can help me figure out how to implement this? Thanks.
Upvotes: 3
Views: 2183
Reputation: 106
update: as of 22.2.1 of the support library the issue has been fixed and there is no more need to save/restore the view state with the workaround mentioned below
Don't use NavigationView.SavedState
NavigationView
is a view with saveEnabled
set to true.
This means that SavedState
should be used internally by the view itself to save/restore its state automatically (E.g: on device rotation)
Unfortunately the view has a confirmed bug and the state is not saved/restored correctly:
https://code.google.com/p/android/issues/detail?id=175224
here you'll find a more general workaround for that issue:
public void onSaveInstance(Bundle outState) {
ArrayList positions = findSelectedPosition();
if(positions.size()>0) {
outState.putIntegerArrayList(STATE_SELECTED_POSITION, positions);
}
}
private ArrayList findSelectedPosition() {
Menu menu = navDrawerFirstPart.getMenu();
int count = menu.size();
ArrayList result = new ArrayList<>();
for (int i = 0; i < count; i++) {
if(menu.getItem(i).isChecked()){
result.add(i);
}
}
return result;
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
if(savedInstanceState.containsKey(STATE_SELECTED_POSITION)){
restoreSelectedPosition(savedInstanceState.getIntegerArrayList(STATE_SELECTED_POSITION));
}
}
private void restoreSelectedPosition(ArrayList<Integer> positions) {
Menu menu = navDrawerFirstPart.getMenu();
for(int i=0; i<positions.size(); i++){
menu.getItem(positions.get(i)).setChecked(true);
}
}
Using a NavigationView.SavedState
would have no pros over this solution, because the state
stored in it, it's a simple Bundle where the NavigationView
stores a SparseBooleanArray
of the check states from the items.
Besides that, the function that start all the process of saving the instance inside the NavigationView
is this:
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
NavigationView.SavedState state = new NavigationView.SavedState(superState);
state.menuState = new Bundle();
this.mMenu.savePresenterStates(state.menuState);
return state;
}
note that savePresenterStates
is part of an internal class MenuBuider
: is public so it's visible, but then again as it is an internal class, should not get accessed outside of the package of the support library. And besides that, tha bundle that comes out of that function is wrong cause it's the root of the issue.
Upvotes: 4