Android - Switch ActionBar Back Button to Navigation Button

AndroidAndroid ActionbarNavigation DrawerAndroid ToolbarBack Button

Android Problem Overview


I am having the following problem:

I know how to set up a toolbar to show a back button icon instead of a burger button icon.

From this:
enter image description here

to this:

enter image description here

using: getSupportActionBar().setDisplayHomeAsUpEnabled(true);


Now, I want to do the reverse action, I want to go from back button icon to burger icon:

enter image description here

to here:

enter image description here

How can I do this?

Update:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setSupportActionBar(mToolbar);
    getSupportActionBar().setDisplayShowTitleEnabled(false);
}

private void enableViews(boolean enable) {
    if(enable) {
        // Enables back button icon
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    } else {
        // TODO: Enables burger icon
    }
}

Android Solutions


Solution 1 - Android

If I assume you're using android.support.v4.widget.DrawerLayout in your layout, then this approach may work for you; I've only tested on API 21 but given it's mostly using the support libraries, it should work (famous last words) on lower or higher targets.

import android.support.v7.app.ActionBarDrawerToggle
import android.support.v4.widget.DrawerLayout



ActionBarDrawerToggle mDrawerToggle;
DrawerLayout drawerLayout;
private boolean mToolBarNavigationListenerIsRegistered = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setSupportActionBar(mToolbar);
    getSupportActionBar().setDisplayShowTitleEnabled(false);
    // Get DrawerLayout ref from layout
    drawerLayout = (DrawerLayout)findViewById(R.id.drawer);
    // Initialize ActionBarDrawerToggle, which will control toggle of hamburger.
    // You set the values of R.string.open and R.string.close accordingly.
    // Also, you can implement drawer toggle listener if you want.
    mDrawerToggle = new ActionBarDrawerToggle (this, drawerLayout, mToolbar, R.string.open, R.string.close);
    // Setting the actionbarToggle to drawer layout
    drawerLayout.addDrawerListener(mDrawerToggle);
    // Calling sync state is necessary to show your hamburger icon...
    // or so I hear. Doesn't hurt including it even if you find it works
    // without it on your test device(s)
    mDrawerToggle.syncState();
}

/**
 * To be semantically or contextually correct, maybe change the name
 * and signature of this function to something like:
 *
 * private void showBackButton(boolean show)
 * Just a suggestion.
 */
 private void enableViews(boolean enable) {

    // To keep states of ActionBar and ActionBarDrawerToggle synchronized,
    // when you enable on one, you disable on the other.
    // And as you may notice, the order for this operation is disable first, then enable - VERY VERY IMPORTANT.
    if(enable) {
        //You may not want to open the drawer on swipe from the left in this case  
        drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
        // Remove hamburger
        mDrawerToggle.setDrawerIndicatorEnabled(false);
        // Show back button
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        // when DrawerToggle is disabled i.e. setDrawerIndicatorEnabled(false), navigation icon
        // clicks are disabled i.e. the UP button will not work.
        // We need to add a listener, as in below, so DrawerToggle will forward
        // click events to this listener.
        if(!mToolBarNavigationListenerIsRegistered) {
            mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // Doesn't have to be onBackPressed
                    onBackPressed();
                }
            });

            mToolBarNavigationListenerIsRegistered = true;
        }
        
    } else {
        //You must regain the power of swipe for the drawer. 
        drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
        
        // Remove back button
        getSupportActionBar().setDisplayHomeAsUpEnabled(false);
        // Show hamburger 
        mDrawerToggle.setDrawerIndicatorEnabled(true);
        // Remove the/any drawer toggle listener
        mDrawerToggle.setToolbarNavigationClickListener(null);
        mToolBarNavigationListenerIsRegistered = false;
    }

    // So, one may think "Hmm why not simplify to:
    // .....
    // getSupportActionBar().setDisplayHomeAsUpEnabled(enable);
    // mDrawer.setDrawerIndicatorEnabled(!enable);
    // ......
    // To re-iterate, the order in which you enable and disable views IS important #dontSimplify.
}


The solution uses ActionBarDrawerToggle.setDrawerIndicatorEnabled to toggle the visibility of the hamburger icon and ActionBar.setDisplayHomeAsUpEnabled for visibility of the Up button, essentially making use of their respective drawable resources.

Other assumptions

  • Your Activity theme extends Theme.AppCompat.Light.NoActionBar.

Solution 2 - Android

The top solutions did not work in this case:

  • One Activity and multiple Fragments
  • One Fragment (SettingsFragment) should show the back icon instead of the burger menu
  • Using com.google.android.material.appbar.AppBarLayout, androidx.appcompat.widget.Toolbar and ActionBarDrawerToggle

I call this method in my Activity's onCreate():

private fun initBackStackChangeListener() {
    supportFragmentManager.addOnBackStackChangedListener {
        val fragment = supportFragmentManager.findFragmentById(R.id.fragment_container)
       
        if (fragment is SettingsFragment) {
            menuDrawerToggle?.isDrawerIndicatorEnabled = false
            drawer_layout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
            menuDrawerToggle?.setToolbarNavigationClickListener { onBackPressed() }
            supportActionBar?.setDisplayHomeAsUpEnabled(true)
        } else {
            supportActionBar?.setDisplayHomeAsUpEnabled(false)
            drawer_layout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
            menuDrawerToggle?.isDrawerIndicatorEnabled = true
            menuDrawerToggle?.toolbarNavigationClickListener = null
            menuDrawerToggle?.syncState()
        }
    }
}

And menuDrawerToggle is this:

menuDrawerToggle = ActionBarDrawerToggle(
        this, drawer_layout, toolbar,
        R.string.navigation_drawer_open,
        R.string.navigation_drawer_close
    ).apply {
        drawer_layout.addDrawerListener(this)
        this.syncState()
    }

Works like a charm. Maybe it helps anybody.

Solution 3 - Android

I found flexible solutions in The Google I/O 2017 Android App.

public Toolbar getToolbar() {
    if (mToolbar == null) {
        mToolbar = (Toolbar) findViewById(R.id.toolbar);
        if (mToolbar != null) {
            setSupportActionBar(mToolbar);
            mToolbar.setNavigationContentDescription(R.string.navdrawer_description_a11y);
            mToolbarTitle = (TextView) mToolbar.findViewById(R.id.toolbar_title);
            if (mToolbarTitle != null) {
                int titleId = getNavigationTitleId();
                if (titleId != 0) {
                    mToolbarTitle.setText(titleId);
                }
            }

            // We use our own toolbar title, so hide the default one
            getSupportActionBar().setDisplayShowTitleEnabled(false);
        }
    }
    return mToolbar;
}

/**
 * @param clickListener The {@link android.view.View.OnClickListener} for the navigation icon of
 *                      the toolbar.
 */
protected void setToolbarAsUp(View.OnClickListener clickListener) {
    // Initialise the toolbar
    getToolbar();
    if (mToolbar != null) {
        mToolbar.setNavigationIcon(R.drawable.ic_up);
        mToolbar.setNavigationContentDescription(R.string.close_and_go_back);
        mToolbar.setNavigationOnClickListener(clickListener);
    }
}

So the usage is really simple.

setToolbarAsUp(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // onBackPressed();
        // or navigate to parent or some other intent
    }
});

Solution 4 - Android

The selected answer is too hacky in my opinion.

I tried implementing it, and while doing so I realized that there's actually no good use for the ActionBarDrawerToggle (maybe that is why it was removed from the official android tutorial regarding Navigation Drawer): it doesn't make your life easier when you want to co-ordinate between the navigate drawer and the action bar.

The problem is that you only have 1 home "button", and that it has 2 different functionalities - open the drawer when you are in the main screen, and go up when you are further down in your app. Passing the toolbar as a parameter to ActionBarDrawerToggle constructor, adds the menu icon to it, and calls openDrawer on click event. Now if you want to switch to an up event you have to turn off this special icon, and re-enable the inherent back functionality of the action bar... which is still a mess.

So if ActionBarDrawerToggle doesn't help you (yet, maybe someone will figure out a way where it does), why use it in the first place? Here's how to do it without it:

boolean homeShouldOpenDrawer; // flag for onOptionsItemSelected

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // if you're using NoActionBar theme
    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    ActionBar actionbar = getSupportActionBar();

    // enables the home button with a <-
    actionbar.setDisplayHomeAsUpEnabled(true);

    // replaces the <- with the menu (hamburger) icon 
    // (ic_menu should be in every empty project, and can be easily added)
    actionbar.setHomeAsUpIndicator(R.drawable.ic_menu);

    // I assume your first fragment/state should be main screen, i.e. home = opens drawer
    homeShouldOpenDrawer = true;
    ...
}

private void enableViews(boolean enable) {
    if(enable) {
        // Enables back button icon
        // passing null or 0 brings back the <- icon
        getSupportActionBar().setHomeAsUpIndicator(null);
        homeShouldOpenDrawer = false;
    } else {
        // Enables burger icon
        getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
        homeShouldOpenDrawer = true;
    }

}

// this is called whenever a selection is made from the action bar
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            if (homeShouldOpenDrawer) {
                drawerLayout.openDrawer(GravityCompat.START);
            } else {
                onBackPressed();
            }
    }

    return super.onOptionsItemSelected(item);
}

Solution 5 - Android

you can change the action bar button with:

        getSupportActionBar().setHomeAsUpIndicator(R.drawable.back_button);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

Solution 6 - Android

I've been trying some of these examples on my App, but none of them seemed to work. I am using fragments and some of them must show the back option instead of home. Here is my implementation (in Kotlin):

override fun onResume() {
    super.onResume()
    var drawerLayout: DrawerLayout = activity.findViewById(R.id.drawer_layout)
    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
    var actionBar = (activity as MainActivity).supportActionBar
    actionBar!!.setDisplayHomeAsUpEnabled(true)
    var  toggle= (activity as MainActivity).drawerToggle
    toggle.isDrawerIndicatorEnabled = false
    toggle.setToolbarNavigationClickListener { v ->  activity.onBackPressed() }
}

override fun onStop() {
    super.onStop()
    var drawerLayout: DrawerLayout = activity.findViewById(R.id.drawer_layout)
    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
    var actionBar = (activity as MainActivity).supportActionBar
    actionBar!!.setDisplayHomeAsUpEnabled(false)
    var  toggle= (activity as MainActivity).drawerToggle
    toggle.setToolbarNavigationClickListener {null}
    toggle.syncState()
}

NOTE: these are the overridden onResume and onStop method inside the fragment.

REMARK: the hamburger icon will only show up if the toggle.syncState() method is called. I've been almost 24 hours figuring out why the home icon wasn't showing.

Hope my post can help someone.

Solution 7 - Android

Use this

getSupportActionBar().setDisplayShowHomeEnabled(true);

Solution 8 - Android

 final Toolbar toolbar = (Toolbar) findViewById(R.id.actionbar);
      toolbar.setTitle(Html.fromHtml("<font color=#ffffff>" +     getString(R.string.print_s) + "</font>"));
      toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.menu_icon));
     toolbar.setNavigationOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
             DetailActivity.this.finish();
        }
    });
    toolbar.inflateMenu(R.menu.fav);
    toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener()     {
        @Override
        public boolean onMenuItemClick(MenuItem item) {
              item.setIcon(R.drawable.back_icon)
              return true;
            }
            return false;
        }
    });

Solution 9 - Android

Try adding below code of style AppTheme to your activity's theme/style.xml it will make your hamburger icon to back icon with animation.

Condition if you are using hamburger icon with NavigationDrawer and AppCompatActivity/ActionBarActivity

<style name="AppTheme" parent="Theme.AppCompat.Light">
            <item name="windowActionBar">false</item>
            <item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
        </style>


<style name="DrawerArrowStyle" parent="Widget.AppCompat.DrawerArrowToggle">
    <item name="spinBars">true</item>
    <item name="color">@android:color/white</item>
</style>

I hope it helps! or you just have to do it with drawable only.

Check this link

Solution 10 - Android

For me, I wanted to change the Burger icon by a Back Arrow icon on the left side of Fragment's ActionBar as I am using a Navigation Drawer. Also Adding a Menu on the right side.

In Main Activity, it's already set - by default when Android Studio create the Navigation Drawer for me - like this:

Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open,
                R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();

The issue is how to customize the ActionBar in the Fragment, so when I go to the Fragment it shall show me the customized ActionBar and when the Back Arrow icon is clicked, it shall leave the fragment and the ActionBar should back to the first state.

In Fragment (Complete Implementation):

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true); // To show the menu options
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState){
    super.onViewCreated(view, savedInstanceState);
    showActionBar(); // the method to change ActionBar
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // inflate the customized menu which already created in XML
    getActivity().getMenuInflater().inflate(R.menu.fragment_menu, menu);
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // add implementation when user select an item from the menu
    switch (item.getItemId()) {
        case R.id.option1:
            // do something
            return true;
        case R.id.option2:
            // do something
            return true;
        case R.id.option3:
            // do something
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

private void showActionBar() {
    // get the ToolBar from Main Activity
    final Toolbar toolbar = getActivity().findViewById(R.id.toolbar);
    // get the ActionBar from Main Activity
    final ActionBar actionBar = ((AppCompatActivity)getActivity()).getSupportActionBar();
    // inflate the customized Action Bar View
    LayoutInflater inflater = (LayoutInflater) getActivity()
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View v = inflater.inflate(R.layout.fragment_actionbar, null);
    
    if (actionBar != null) {
        // enable the customized view and disable title
        actionBar.setDisplayShowCustomEnabled(true);
        actionBar.setDisplayShowTitleEnabled(false);
       
        actionBar.setCustomView(v);
        // remove Burger Icon
        toolbar.setNavigationIcon(null);

        // add click listener to the back arrow icon
        v.findViewById(R.id.back).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // reverse back the show
                actionBar.setDisplayShowCustomEnabled(false);
                actionBar.setDisplayShowTitleEnabled(true);
                //get the Drawer and DrawerToggle from Main Activity
                // set them back as normal
                DrawerLayout drawer = getActivity().findViewById(R.id.drawer_layout);
                ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                        getActivity(), drawer, toolbar, R.string.navigation_drawer_open,
                        R.string.navigation_drawer_close);
                // All that to re-synchronize the Drawer State
                toggle.syncState();
                // Implement Back Arrow Icon 
                // so it goes back to previous Fragment
                getActivity().onBackPressed();
            }
        });
    }
}

fragment_actionbar.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="match_parent"
    android:layout_gravity="fill_horizontal" >

    <ImageView
        android:id="@+id/back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:src="@drawable/ic_menu_back"
        android:layout_marginLeft="@dimen/_5sdp"
        android:layout_alignParentStart="true"
        android:layout_marginStart="@dimen/_5sdp" />

</RelativeLayout>

ic_menu_back.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportHeight="459"
    android:viewportWidth="459">
    <path
        android:fillColor="#ffffff"
        android:pathData="M178.5,140.25v-102L0,216.75l178.5,178.5V290.7c127.5,0,216.75,40.8,280.5,130.05C433.5,293.25,357,165.75,178.5,140.25z"/>
</vector>

fragment_menu.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="@drawable/border_shadow">

    <item
        android:id="@+id/option1"
        android:title="@string/show_profile"
        app:showAsAction="never"/>
    <item
        android:id="@+id/option2"
        android:title="@string/report_pic"
        app:showAsAction="never"/>
    <item
        android:id="@+id/option3"
        android:title="@string/delete_pic"
        app:showAsAction="never"/>
</menu>

Solution 11 - Android

-> If you have a drawer on homeactivity and initalfragment you have to show the drawertoggle and after inner fragement you don't want to show the drawer behalf of drawer you have to show the back button and change the title of all fragement like this.

  • make your actionbartoggle public in your activity.

  • in your home fragment write this code.

      @Override
    
      public void onResume() 
    
      {
          super.onResume();
      
          ((HomeActivity)getActivity()).getSupportActionBar().setTitle("Home");
      
          ((HomeActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
      
          ((HomeActivity)getActivity()).actionBarDrawerToggle.setDrawerIndicatorEnabled(true);}    
    
  • and in other fragments write this code :

           @Override
          public void onResume() 
      {     super.onResume();
              ((HomeActivity)getActivity()).getSupportActionBar().setTitle("My Account");
              ((HomeActivity)getActivity()).actionBarDrawerToggle.setDrawerIndicatorEnabled(false);
              ((HomeActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
          }
    
  • and in your main activity write in on backpressed :

      @Override
          public void onBackPressed() 
          {
              if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
    
                  getSupportFragmentManager().popBackStackImmediate();
      
              } else {
      
                  super.onBackPressed();
      
              }
          }
    

Solution 12 - Android

I have the simplest solution for Kotlin Developers

Just add this in your root activity where fragments resist

if (supportFragmentManager.backStackEntryCount > 0) {
  supportActionBar!!.setDisplayHomeAsUpEnabled(true)
  toolbar.setNavigationOnClickListener {
      if (supportFragmentManager.backStackEntryCount > 0) {
          super.onBackPressed()
      } else {
          supportActionBar!!.setDisplayHomeAsUpEnabled(false)
          drawerLayout.addDrawerListener(toggle)
          toggle.syncState()
          drawerLayout.openDrawer(GravityCompat.START)
      }
  }
} else {
  supportActionBar!!.setDisplayHomeAsUpEnabled(false)
  drawerLayout.addDrawerListener(toggle)
  toggle.syncState()
}

Here, whenever setDisplayHomeAsUpEnabled is set true , I am showing back button. and on cliking it, I am calling super.onBackPressed() which is similar to what your back button does!

Solution 13 - Android

You can use following to show the back button instead of Navigation menu.

(activity as MainActivity).supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAntonioView Question on Stackoverflow
Solution 1 - Androidade.akinyedeView Answer on Stackoverflow
Solution 2 - AndroidStefanToView Answer on Stackoverflow
Solution 3 - AndroidAnton PelykhView Answer on Stackoverflow
Solution 4 - AndroidMaverick MeerkatView Answer on Stackoverflow
Solution 5 - AndroidMartín HuergoView Answer on Stackoverflow
Solution 6 - AndroidalexscmarView Answer on Stackoverflow
Solution 7 - AndroidRam Prakash BhatView Answer on Stackoverflow
Solution 8 - AndroidDineshView Answer on Stackoverflow
Solution 9 - AndroidShishramView Answer on Stackoverflow
Solution 10 - AndroidYahyaView Answer on Stackoverflow
Solution 11 - AndroidHardik DudhaiyaView Answer on Stackoverflow
Solution 12 - AndroidKishan SolankiView Answer on Stackoverflow
Solution 13 - AndroidAkash BisariyaView Answer on Stackoverflow