Reputation: 965
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
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
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
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
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
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
Reputation: 7788
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.
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