Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add back button to Toolbar for all Fragments other than Home Fragment which opens Navigation Drawer

Tags:

When my application is opened Home screen is shown first.On Home screen I have NavigationDrawer which get opened after pressing HamburgerIcon.Later i go to different fragments.When I am in Other fragments other than Home Activity I need to show back button on Toolbar to come to previous fragment.But its every time showing Hamburger icon.How to do this ?
This is code for setting Toolbar in XML

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/drawerLayout"
    tools:context="biz.fyra.myApp.ActivityTwo">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#ccc"
            android:minHeight="?attr/actionBarSize">
            <ImageView
                android:id="@+id/tooImage"
                android:src="@drawable/latest"
                android:layout_width="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_height="40dp" />
        </android.support.v7.widget.Toolbar>
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/frame">
        </FrameLayout>
    </LinearLayout>
    <android.support.design.widget.NavigationView
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/nav_header"
        android:id="@+id/navigationView"
        app:menu="@menu/actionmenu"
        android:background="@android:color/white">
    </android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>  

How to achieve this ?

like image 538
Satyam Gondhale Avatar asked Mar 29 '18 12:03

Satyam Gondhale


People also ask

Which method is called when back button is pressed in fragment?

onBackPressed() method. In its body, we list all fragments attached to activity and for this implementing our BaseFragment class/interface we notify them about the new back-press event.

What is the Back button on Android?

The Back button appears in the system navigation bar at the bottom of the screen and is used to navigate in reverse-chronological order through the history of screens the user has recently worked with.


1 Answers

If i understand right, you are using one activity with fragments replacing. So, looking at that you would have something like this:

Important: Activity theme should extends Theme.AppCompat.Light.NoActionBar


Activity:

public class MainActivity extends AppCompatActivity
    implements NavigationView.OnNavigationItemSelectedListener {
private DrawerLayout drawer;
private Toolbar toolbar;
private ActionBarDrawerToggle toggle;

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

    drawer = findViewById(R.id.drawer);
    toolbar = findViewById(R.id.toolbar);

    setSupportActionBar(toolbar);
    toggle = new ActionBarDrawerToggle(
            this,
            drawer,
            toolbar,
            R.string.navigation_drawer_open,
            R.string.navigation_drawer_close
    );
    drawer.addDrawerListener(toggle);
    toggle.syncState();

    NavigationView navigationView = findViewById(R.id.nav_view);
    navigationView.setNavigationItemSelectedListener(this);

    // First creation
    if (savedInstanceState == null)
        showFragment(StartFragment.newInstance());
}
/**
* Using in Base Fragment
*/
protected ActionBarDrawerToggle getToggle() {
    return toggle;
}

@Override
public void onBackPressed() {
    Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.frame);

    if (drawer.isDrawerOpen(GravityCompat.START)) {
        drawer.closeDrawer(GravityCompat.START);
    } else if (fragment instanceof OnBackPressedListener) {
        ((OnBackPressedListener) fragment).onBackPressed();
    } else {
        super.onBackPressed();
    }
}

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    drawer.closeDrawer(GravityCompat.START);
    switch (item.getItemId()) {
        case R.id.start: {
            showFragment(StartFragment.newInstance());
            break;
        }
        case R.id.orders: {
            showFragment(OrdersFragment.newInstance());
            break;
        }
        case R.id.category: {
            showFragment(CategoryFragment.newInstance());
            break;
        }
        case R.id.calendar: {
            showFragment(CalendarFragment.newInstance());
            break;
        }
        case R.id.settings: {
            showFragment(SettingsFragment.newInstance());
            break;
        }
        case R.id.about: {
            showFragment(AboutFragment.newInstance());
            break;
        }
    return true;
}

private void showFragment(Fragment fragment) {
    getSupportFragmentManager().beginTransaction().replace(R.id.frame, fragment).commit();
}
}

Interface for sending backpress events from activity to fragments:

public interface OnBackPressedListener {
    void onBackPressed();
}

And Abstract Base Fragment which you should extends and implement methods:

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;

import ...
/**
 * Abstract fragment with FAB button, Toolbar and 2 interfaces: 
OnClick, OnBackPress
 *
 */
public abstract class BaseFragment extends Fragment implements 
View.OnClickListener, OnBackPressedListener {

protected FloatingActionButton fab;
protected Toolbar toolbar;
protected ActionBar actionBar;
protected ActionBarDrawerToggle toggle;
protected DrawerLayout drawer;
protected boolean mToolBarNavigationListenerIsRegistered = false;

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    fab = ((MainActivity)getActivity()).findViewById(R.id.fab);
    toolbar = ((MainActivity) getActivity()).findViewById(R.id.toolbar);
    actionBar = ((MainActivity) getActivity()).getSupportActionBar();
    drawer = ((MainActivity) getActivity()).findViewById(R.id.drawer_layout);
    toggle = ((MainActivity) getActivity()).getToggle();
    fab.setOnClickListener(this);
}

/**
* Simplify fragment replacing in child fragments
*/
protected void replaceFragment(@NonNull Fragment fragment) {
    FragmentManager fm = getActivity().getSupportFragmentManager();
    fm.beginTransaction().replace(R.id.container, fragment).commit();
}

// hide FAB button
protected void hideFab() {
    fab.hide();
}

//show FAB button
protected void showFab() {
    fab.show();
}

/**
 * Shows Home button as Back button
 * Took from here {@link}https://stackoverflow.com/a/36677279/9381524
 * <p>
 * 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!!!
 *
 * @param show = true to show <showHomeAsUp> or show = false to show <Hamburger> button
 */
protected void showBackButton(boolean show) {

    if (show) {
        // Remove hamburger
        toggle.setDrawerIndicatorEnabled(false);
        // Show back button
        actionBar.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) {
            toggle.setToolbarNavigationClickListener(v -> onBackPressed());
            mToolBarNavigationListenerIsRegistered = true;
        }

    } else {
        // Remove back button
        actionBar.setDisplayHomeAsUpEnabled(false);
        // Show hamburger
        toggle.setDrawerIndicatorEnabled(true);
        // Remove the/any drawer toggle listener
        toggle.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.
}

/**
* Simplify setTitle in child fragments
*/
protected void setTitle(int resId) {
    getActivity().setTitle(getResources().getString(resId));
}

//
@Override
public abstract void onClick(View v);

// Handles BackPress events from MainActivity
@Override
public abstract void onBackPressed();
}

All fragments with Back Button used in MainActivity should extends from this BaseFragment.

like image 62
Jurij Pitulja Avatar answered Sep 23 '22 12:09

Jurij Pitulja