Mike Mike - 3 months ago 13
Android Question

Slide out navigation items staying highlighted

In my Android app I have a slide out navigation drawer. When An item is selected in the navigation drawer, it loads the new fragment and highlights the item you clicked on in the navigation drawer.

My issue is that in the new fragment that loaded you can click on a new item within that fragment which loads a new fragment and still keeps the navigation drawer.

At this instance you are no longer on a fragment that is listed in the navigation drawer but the last item is still highlighted and then can not be clicked again to go back.

Any ideas on how I can un-highlight an item in the navigation drawer when it is not one of my main fragments and then be re-highlighted if on one of the main fragments?

Here is my navigation drawer code:

public class MainDrawer2 extends FragmentActivity
{
private static final String EXTRA_NAV_ITEM = "extraNavItem";
private static final String STATE_CURRENT_NAV = "stateCurrentNav";

private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;

private NavDrawerListAdapter mDrawerAdapter;
private ListView mDrawerList;

private CharSequence mTitle;
private CharSequence mDrawerTitle;

private MainNavItem mCurrentNavItem;




public static Intent createLaunchFragmentIntent(Context context, MainNavItem navItem)
{
return new Intent(context, MainDrawer2.class)
.putExtra(EXTRA_NAV_ITEM, navItem.ordinal());
}



@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);

Crashlytics.start(this);



mTitle = mDrawerTitle = getTitle();
mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
mDrawerList = (ListView)findViewById(R.id.drawer);

getActionBar().setDisplayHomeAsUpEnabled(true);
enableHomeButtonIfRequired();

mDrawerAdapter = new NavDrawerListAdapter(getApplicationContext());
mDrawerList.setAdapter(mDrawerAdapter);
mDrawerList.setOnItemClickListener(new ListView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
displayNavFragment((MainNavItem)parent.getItemAtPosition(position));
}
});

mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, R.string.app_name, R.string.app_name)
{
public void onDrawerClosed(View view)
{
getActionBar().setTitle(mTitle);
invalidateOptionsMenu();
}

public void onDrawerOpened(View drawerView)
{
getActionBar().setTitle(mDrawerTitle);
invalidateOptionsMenu();
}
};

mDrawerLayout.setDrawerListener(mDrawerToggle);

if(getIntent().hasExtra(EXTRA_NAV_ITEM)){
MainNavItem navItem = MainNavItem.values()
[getIntent().getIntExtra(EXTRA_NAV_ITEM,
MainNavItem.STATISTICS.ordinal())];
displayNavFragment(navItem);
}
else if(savedInstanceState != null){
mCurrentNavItem = MainNavItem.values()
[savedInstanceState.getInt(STATE_CURRENT_NAV)];
setCurrentNavItem(mCurrentNavItem);
}
else{
displayNavFragment(MainNavItem.STATISTICS);
}
}

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void enableHomeButtonIfRequired()
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH){
getActionBar().setHomeButtonEnabled(true);
}
}
public void setActionBarTitle(String title) {
getActionBar().setTitle(title);
}


@Override
public void setTitle(CharSequence title)
{
mTitle = title;
getActionBar().setTitle(mTitle);
}

@Override
protected void onPostCreate(Bundle savedInstanceState)
{
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}

@Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggles
mDrawerToggle.onConfigurationChanged(newConfig);
}

@Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putInt(STATE_CURRENT_NAV, mCurrentNavItem.ordinal());
}

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

/*
@Override
public boolean onPrepareOptionsMenu(Menu menu)
{
// if nav drawer is opened, hide the action items
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
*/



private void displayNavFragment(MainNavItem navItem)
{
if(navItem == mCurrentNavItem){
return;
}
Fragment fragment = Fragment.instantiate(this,
navItem.getFragClass().getName());
if(fragment != null){

getSupportFragmentManager().beginTransaction()
.replace(R.id.main, fragment)
.commit();
setCurrentNavItem(navItem);
}
}

private void setCurrentNavItem(MainNavItem navItem)
{
int position = navItem.ordinal();
// If navItem is in DrawerAdapter
if(position >= 0 && position < mDrawerAdapter.getCount()){
mDrawerList.setItemChecked(position, true);
}
else{
// navItem not in DrawerAdapter, de-select current item
if(mCurrentNavItem != null){
mDrawerList.setItemChecked(mCurrentNavItem.ordinal(), false);
}
}
mDrawerLayout.closeDrawer(mDrawerList);
setTitle(navItem.getTitleResId());
mCurrentNavItem = navItem;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if(mDrawerLayout.isDrawerOpen(mDrawerList)) {
mDrawerLayout.closeDrawer(mDrawerList);
}
else {
mDrawerLayout.openDrawer(mDrawerList);
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}




public void goToSearch(MenuItem item){

//go to search page
Fragment Fragment_one;
FragmentManager man= getSupportFragmentManager();
FragmentTransaction tran = man.beginTransaction();
Fragment_one = new Search();

tran.replace(R.id.main, Fragment_one);//tran.
tran.addToBackStack(null);
tran.commit();

}

public void scanBarcode(MenuItem item){

//open scanner
IntentIntegrator scanIntegrator = new IntentIntegrator(this);
scanIntegrator.initiateScan();



}

public void onActivityResult(int requestCode, int resultCode, Intent intent) {

//retrieve scan result
IntentResult scanningResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
if (scanningResult != null) {
//we have a result

String scanContent = scanningResult.getContents();

//todo: set scan content into setting, load new fragment which calls async task below. New
//todo: fragment will have same ui as search. :-)
Fragment Fragment_one;
FragmentManager man= this.getSupportFragmentManager();
FragmentTransaction tran = man.beginTransaction();
Fragment_one = new BarcodeFrag(scanContent);
tran.replace(R.id.main, Fragment_one);//tran.
tran.addToBackStack(null);
//tran.commit();
tran.commitAllowingStateLoss();


}

else{
Toast toast = Toast.makeText(getApplicationContext(),
"No scan data received!", Toast.LENGTH_SHORT);
toast.show();
}

}


}


then I have an enum called main nav item:

public enum MainNavItem
{
// Displayed in NavDrawerListAdapter
STATISTICS("Your Statistics", R.layout.statistics_pagelayout, StatisticsTab.class),
DISCOVER ("Discover", R.layout.activity_discover, DiscoverTab.class),
PORTFOLIO ("Portfolio", R.layout.activity_portfolio, Portfolio.class),
LISTS ("Your Lists", R.layout.activity_search, AllLists.class),
NEWS ("News", R.layout.activity_news, NewsWeb.class),
Find ("Nearby Breweries", R.layout.beer_location_list, FindBrewery.class),
CONTACT ("Contact", R.layout.activity_contact, ContactPage.class),
// Items NOT displayed in NavDrawerListAdapter
SEARCH ("Search", R.layout.activity_search, Search.class),
;

private static MainNavItem LAST_NAV_ITEM = CONTACT;

private String mTitleResId;
private int mLayoutResId;
private Class<? extends Fragment> mFragClass;


private MainNavItem(String titleResId, int layoutResId, Class<? extends Fragment> fragClass)
{
mTitleResId = titleResId;
mLayoutResId = layoutResId;
mFragClass = fragClass;
}

public int getLayoutResId()
{
return mLayoutResId;
}

public String getTitleResId()
{
return mTitleResId;
}

public Class<? extends Fragment> getFragClass()
{
return mFragClass;
}

public static MainNavItem[] getNavAdapterItems()
{
int count = LAST_NAV_ITEM.ordinal() + 1;

MainNavItem[] adapterItems = new MainNavItem[count];
for(int i = 0; i < count; i++){
adapterItems[i] = values()[i];
}

return adapterItems;
}
}


UPDATE:

I just tried to comment out these two lines to turn off highlighting in general so a user can re-select an item again in my navigation drawer.

private void setCurrentNavItem(MainNavItem navItem)
{
int position = navItem.ordinal();
// If navItem is in DrawerAdapter
if(position >= 0 && position < mDrawerAdapter.getCount()){
//mDrawerList.setItemChecked(position, true);
}
else{
// navItem not in DrawerAdapter, de-select current item
if(mCurrentNavItem != null){
//mDrawerList.setItemChecked(mCurrentNavItem.ordinal(), false);
}
}
mDrawerLayout.closeDrawer(mDrawerList);
setTitle(navItem.getTitleResId());
mCurrentNavItem = navItem;
}


When the app boots for the firs time now, nothing is highlighted, but when I click on something it get highlighted and I can not click it again to reload that fragment. Any other ideas?

Answer

Figured it out. The simplest way to not have an item in your draw be highlighted is in your xml for the draw linst, choiceMode should be none:

<FrameLayout
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
</FrameLayout>

<ListView
    android:id="@+id/drawer"
    android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:divider="@android:color/white"
    android:background="@android:color/black"
    android:choiceMode="none"/>