I have a question. I'm using android navigation architecture components, using bottom navigation view with singl activity. How can I make a fragment open only once? Even if the button that causes this fragment is clicked several times? How to make a fragment to be added to the back stack only once? I created a test project for try it
xml navigation_test
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/test_nav"
app:startDestination="@id/firstFragment">
<fragment
android:id="@+id/firstFragment"
android:name="ru.artem_nr.navigation_test.FirstFragment"
android:label="fragment_first"
tools:layout="@layout/fragment_first" >
<action
android:id="@+id/action_firstFragment_to_secondFrag"
app:destination="@id/navigation"
app:launchSingleTop="true"
app:popUpTo="@+id/secondFrag"
app:popUpToInclusive="false" />
</fragment>
<navigation android:id="@+id/navigation"
app:startDestination="@id/secondFrag">
<fragment
android:id="@+id/secondFrag"
android:name="ru.artem_nr.navigation_test.SecondFrag"
android:label="fragment_second"
tools:layout="@layout/fragment_second" />
</navigation>
</navigation>
main_activity
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
public Toolbar toolbar;
public DrawerLayout drawerLayout;
public NavController navController;
public NavigationView navigationView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupNavigation();
}
private void setupNavigation() {
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
drawerLayout = findViewById(R.id.drawer_layout);
navigationView = findViewById(R.id.nav_view);
navController = Navigation.findNavController(this, R.id.garden_nav_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout);
NavigationUI.setupWithNavController(navigationView, navController);
navigationView.setNavigationItemSelectedListener((NavigationView.OnNavigationItemSelectedListener) this);
}
@Override
public boolean onSupportNavigateUp() {
return (boolean) NavigationUI.navigateUp(navController, drawerLayout);
}
@Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
menuItem.setChecked(true);
drawerLayout.closeDrawers();
int id = menuItem.getItemId();
switch (id) {
case R.id.nav_home:
navController.navigate(R.id.navigation);
break;
}
return true;
}
}
fragments - just a blank
As per this issue, BottomNavigationView offers a OnNavigationItemReselectedListener that takes precedence over the OnNavigationItemSelectedListener set by NavigationUI:
bottomNavigationView.setOnNavigationItemReselectedListener(
new BottomNavigationView.OnNavigationReselectedListener() {
@Override
public void onNavigationItemReselected(MenuItem item) {
// By doing nothing, we ignore reselection events
}
});
NavigationView does not offer the same interface, as per this other issue, so you'd want to copy the default behavior (note that it calls NavigationUI.onNavDestinationSelected() and not just call navigate() directly, unlike your code) and add your own check for isChecked() to guard against reselection.
You need to declare the fragment as "SingleTop".
There is an option on the menu in the right hand side of the navigation graph editor view to do this, below the animation options.
Alternatively you can set it programmatically through the NavOptions.Builder class, using the setLaunchSingleTop(true) method as detailed in the link below:
https://developer.android.com/reference/kotlin/androidx/navigation/NavOptions.Builder#setLaunchSingleTop(kotlin.Boolean)
So your on select method should look like:
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem){
NavOptions.Builder builder = new NavOptions.Builder()
.setLaunchSingleTop(true);
NavOptions options = builder.build();
navController.navigate(item.getItemId(), null, options);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With