Android - Switch ActionBar Back Button to Navigation Button
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.ActionBarDrawerToggleimport 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
.
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.
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 }});