Arbaz Pirwani
Arbaz Pirwani

Reputation: 965

How to close navigation DrawerLayout onBackPressed in Navigation Controls Fragment

I have created an Androidx project with Navigation pattern. Now I want to close drawerLayout onBackPressed() in fragment. And also I want to set OnClickListener to drawer menu items to my custom menu there is no way I guess to override the onBackPressed() in fragment.

I want to know how I can achieve this?

Here is my drawer:

<androidx.drawerlayout.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:id="@+id/drawerLayoutHome"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="350dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="@color/colorPrimaryDark"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:itemIconTint="@color/white"
        app:itemTextColor="@color/white"
        app:menu="@menu/activity_main_drawer"/>

</androidx.drawerlayout.widget.DrawerLayout>

I want to achieve this:

override fun onBackPressed() {

    if (drawerLayoutHome.isDrawerOpen(GravityCompat.END)) {
        drawerLayoutHome.closeDrawer(GravityCompat.END)
    } else {
        super.onBackPressed()
    }
}

But this is for Activity, how to achieve this in Fragment?

Upvotes: 18

Views: 4792

Answers (6)

tfad334
tfad334

Reputation: 598

You can control onBackPress() from within fragments with OnBackPressedDispatcher.

class SampleFragment: Fragment() {
 
    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
        
        requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true){
            override fun handleOnBackPressed() {
                if (drawer.isDrawerOpen(GravityCompat.START)) {
                    drawer.closeDrawer(GravityCompat.START)
                } else{
                    isEnabled = false
                    requireActivity().onBackPressed() }}
                }
            })
        }
 }

Upvotes: 1

sanjeev
sanjeev

Reputation: 1675

I have had a similar problem.

So, I added this in onBackPressed of my Activity file.

FragmentManager manager = getSupportFragmentManager();
 if (manager.getBackStackEntryCount() > 0) {
                while (manager.getBackStackEntryCount() > 0) {
                    manager.popBackStackImmediate();
                }

Upvotes: 0

Hello world
Hello world

Reputation: 90

Hello there you can do it by getting your fragment in activity and override onbackpress with kotlin code

This is your backpress function and in this you can get your nav host and then you can check your current fragment or the fragment you want to open drawer in .

override fun onBackPressed() {

    val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragmentHomeHost)
    val completeFragmentList = navHostFragment?.childFragmentManager?.fragments

    if (completeFragmentList != null) {
        when {
            completeFragmentList[0] is HomeFragment -> {
                val home = (completeFragmentList[0] as HomeFragment)


            }
            else -> super.onBackPressed()
        }
    }

    if (drawerLayoutHome.isDrawerOpen(GravityCompat.START)) {
        drawerLayoutHome.closeDrawer(GravityCompat.START)
    } else {
        super.onBackPressed()
    }
}

And here is hoe you can get selection item listener

override fun onNavigationItemSelected(item: MenuItem): Boolean {
    drawerLayoutHome.closeDrawer(GravityCompat.START)

    return true
}

Upvotes: 8

Mehul Solanki
Mehul Solanki

Reputation: 1141

You can do that within a Fragment by implementing OnBackStackChangedListener on your drawer activity.
Then, link your drawer with ActionBarDrawerToggle and override onBackStackChanged() and synchronize your drawer toggle.

Here is the full snippet:

public class MainActivity extends AppCompatActivity implements FragmentManager.OnBackStackChangedListener {


    private DrawerLayout drawer;
    private ActionBarDrawerToggle toggle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //Bind listener here
        getSupportFragmentManager().addOnBackStackChangedListener(this);
        drawer = findViewById(R.id.drawer_layout);
        toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        toggle.setToolbarNavigationClickListener(view -> onBackPressed());
        drawer.addDrawerListener(toggle);
        toggle.syncState();

    }


    //Override fragment backstack lister method 
    @Override
    public void onBackStackChanged() {
        //toggle.setDrawerIndicatorEnabled(getSupportFragmentManager().getBackStackEntryCount() == 0);
        //getSupportActionBar().setDisplayHomeAsUpEnabled(getSupportFragmentManager().getBackStackEntryCount() > 0);
        toggle.syncState();
    }

    @Override
    public void onBackPressed() {
        drawer = findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START))
            drawer.closeDrawer(GravityCompat.START);
        else {
            //super.onBackPressed();
        }
    }
}

I hope this will help you.

Upvotes: 4

Zeeshan Ayaz
Zeeshan Ayaz

Reputation: 1038

In Kotlin, simply override this method in your activity,

override fun onBackPressed() {
    if (drawer_layout.isDrawerOpen(GravityCompat.START))
        drawer_layout.closeDrawer(GravityCompat.START)
    else
        super.onBackPressed()
}

Upvotes: 2

xinaiz
xinaiz

Reputation: 7788

Short answer

It's not possible to intercept onBackPressed callback inside Fragment without adding additional code inside hosting Activity. It's simply not implemented in Android SDK. Just stop.

Original answer

There is no such thing as onBackPressed callback in Fragment class. But you can implement it yourself:

Create an interface:

interface FragmentOnBackPressedListener {
  fun onBackPressed()
}

Now in your activity:

override fun onBackPressed() {
  // find top fragment
  val currentFragment = supportFragmentManager
    .findFragmentById(R.id.your_nav_host_fragment_id)?.let {
      it.childFragmentManager.fragments.getOrNull(0)
    }
  // check if it implements FragmentOnBackPressedListener 
  if (currentFragment is FragmentOnBackPressedListener ) {
    // if it does, transfer flow to the fragment
    return currentFragment.onBackPressed()
  }
  // if it doesn't, apply default behaviour
  super.onBackPressed()
}

Then in your fragment:

class ExampleFragment : Fragment(), FragmentOnBackPressedListener {

  override fun onBackPressed() {
    // close your drawer layout here if visible

    // Also: to close fragment, invoke 
    // findNavController().navigateUp() or findNavController().popBackStack()
  }

}

Upvotes: 2

Related Questions