I am using a Navigation Drawer and the hamburger menu is showing in all the right screens, but on the other fragments, when I click on the back arrow, the navigation drawer opens when I want to go back in the stack to the previous screen.
How do I change the behavior so that when the arrow is showing, as opposed to the hamburger menu, I can capture the user clicking on the arrow?
I am using a Navigation Drawer with Fragments. In the main activity I am setting the top level destinations with the AppBarConfiguration:
AppBarConfiguration config = new AppBarConfiguration.Builder(topLevelDestinations)
.setDrawerLayout(drawerLayout)
.build();
NavigationUI.setupActionBarWithNavController(this, navController, config);
NavigationUI.setupWithNavController(navView, navController);
navView.setNavigationItemSelectedListener(this);
I am catching all the selections from the top level destinations and navigating appropriately:
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
item.setChecked(true);
drawerLayout.closeDrawers();
int id = item.getItemId();
switch (id) {
...
}
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
The getFragmentManager().popBackStack() method is probably what you are looking for. Here's a sample snippet to be placed for activity:
#Override
public void onBackPressed(){
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
Log.i("MainActivity", "popping backstack");
fm.popBackStack();
} else {
Log.i("MainActivity", "nothing on backstack, calling super");
super.onBackPressed();
}
}
In case of fragments, try calling the fragment like this:
getSupportFragmentManager().beginTransaction()
.add(detailFragment, "detail") // Add this transaction to the back stack
.addToBackStack(null)
.commit();
Related
I handle my back navigation like such:
When creating / committing a Fragment:
getSupportFragmentManager()
.beginTransaction()
.addToBackStack("ToDoFragment")
.replace(R.id.content_frame, fragmentR, fragmentR.getClass().getSimpleName())
.commit();
When catching a back button press:
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
// If navigation drawer is open, close it
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
setDrawerState(true);
displayMenu(true);
}
}
This works fine for my Fragments, but I wish to do the same for my PreferenceFragment, that I call like such:
getFragmentManager().beginTransaction()
.add("ToDoFragment")
.replace(R.id.content_frame, new SettingsFragment()).commit();
But when pressing my back nav. button it does not bring me back to the previous Fragment, instead it overlaps my Settings view and my previous Fragment.
What am I missing / not understanding?
EDIT:
I have added getFragmentManager().popBackStackImmediate(); to my onBackPressed() method, I do not have any view overlapping, but when going into my settings and pressing back, the Fragment is empty.
Using a PreferenceFragment you canĀ“t override onBackPressed() in this case use onDetach() :
#Override
public void onDetach() {
super.onDetach();
//Do your process here!
}
Instead of using 'add' in manager use 'addtoBackStack' Because add retains the existing fragments and adds a new fragment which means existing fragment will be active. Hence back button is not called for existing fragment.
getFragmentManager().beginTransaction()
.addToBackStack("ToDoFragment")
.replace(R.id.content_frame, new SettingsFragment()).commit();
I have Base Activity including NavigationView with 2 menu items. On start it loads Home fragment having background image inside it. Each loads specific fragment. When I select Terms & Conditions menu item, it loads T&C fragment & when I press back button it simply kills it.
However, when I select About Us menu item, it loads About Us fragment but I need to press BACK button twice to kill it. I need to know why does it happen?
Part of Code in AppBaseActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
HomeFragment homeFragment = new HomeFragment();
fragmentTransaction.add(R.id.body_container, homeFragment, "");
fragmentTransaction.commit();
}
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
navigationView.getMenu().findItem(item.getItemId()).setChecked(true);
switch (item.getItemId()) {
case R.id.nav_terms :
fragmentTransaction = fragmentManager.beginTransaction();
TCFragment tcFragment = new TCFragment();
fragmentTransaction.replace(R.id.body_container, tcFragment, "");
fragmentTransaction.commit();
break;
case R.id.nav_about_us :
fragmentTransaction = fragmentManager.beginTransaction();
AboutUsFragment aboutUsFragment = new AboutUsFragment();
fragmentTransaction.replace(R.id.body_container, aboutUsFragment, "");
fragmentTransaction.commit();
break;
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
All fragments simply have overridden onCreateView() by inflating respected xml only. No code is written in both fragments yet.
You can stop back hardware navigation if you want.
Simply using onBackPressed() without super.onBackPressed()
#Override
public void onBackPressed() {
}
#Override
public void onBackPressed() {
super.onBackPressed();
}
I am building an android application using default Navigation Drawer layout and Fragment to switch from one layout to another.
The layout sequence is like
Dashboard -> Settings -> Profile Settings
MailActivity.class loads main_activity.xml which containes a frameLayout to contain fragment
and Dashboard loads ActivityDashboard Fragment.
Now, when I switch from Dashboard to Settings and then Profile Settings. onBackPress works fine. But after on Profile Settings, I selected Dashboard from Navigation Drawer to go back to the home screen. Then pressing back key follows the stack
Dashboard -> Profile Settings -> Settings -> Dashboard
The code for Navigation Drawer is
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// calling the method displaySelectedScreen()
displaySelectedScreen(item.getItemId());
return true;
}
private void displaySelectedScreen(int itemId) {
// creating Fragment object
Fragment fragment = null;
// initializing fragment
switch (itemId) {
case R.id.nav_dashboard:
fragment = new ActivityDashboard();
break;
case R.id.nav_calendar:
fragment = new ActivityCalendar();
break;
case R.id.nav_history:
fragment = new ActivityHistory();
break;
case R.id.nav_about:
fragment = new ActivityAbout();
break;
case R.id.nav_settings:
fragment = new ActivitySettings();
break;
}
// replacing the fragment
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(null);
ft.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
I'm using same FragmentTransaction code to switch from one fragment to another in ActivityDashboard, ActivitySettings fragment classes.
Q 1. How to flush the addBackToStack when the ActivityDashboard is loaded so that user have only option to exit app ?
Q 2. How to get back to ActivityDashboard, when layout is changed from Navigation Drawer irespective of which fragment is replaced ?
i.e., When user is on ActivitySettings fragment and changed to ActivityHistory from Navigation Drawer, then on backPress, user must be tracked following
ActivityHistory -> ActivityDashboard
instead of
ActivityHistory -> ActivitySettings -> ActivityDashboard
onBackPressed() method on MainActivity.class is
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
Simply call
fragmentManager.popBackStack(stackName /* null if you did not supply a stack name while creating your fragments */, FragmentManager.POP_BACK_STACK_INCLUSIVE);
inside your ActivityDashboard
I have an app which utilized NavigationDrawer and toolbar. When I click on one of the menu in the NavigationDrawer, it displays a fragment (let's call it fragment1). Inside fragment1 is a button, when clicked would display another fragment (fragment2).
Ok so when I'm at fragment1, the toolbar would display a hamburger icon, where when I click on it, the drawer would be opened. And when I'm at fragment2, the toolbar would display a back icon (up caret) instead of the hamburger. Ok this is correct, but when I click on the back icon (up caret) the drawer would be opened instead. So what should I do so that when the back icon (up caret) is clicked, I'd be brought back to fragment1, and not opening the drawer?
This is my onClick for the drawer
#Override
public void onClick(View v) {
int position = getPosition();
Fragment fragment = null;
FragmentManager fManager = ((FragmentActivity) contxt).getSupportFragmentManager();
FragmentTransaction transaction = fManager.beginTransaction();
Toast.makeText(contxt, "The Item Clicked isss: " + position, Toast.LENGTH_SHORT).show();
mDrawerLayout = (DrawerLayout) ((FragmentActivity) contxt).findViewById(R.id.dlMainDrawer);
mDrawerLayout.closeDrawers();
switch (position) {
case 1:
fragment = new MenuHome();
transaction.replace(R.id.container, fragment, "fragmentHome");
transaction.addToBackStack(null);
transaction.commit();
break;
case 2:
fragment = new MenuExpensesDaily();
transaction.replace(R.id.container, fragment, "fragmentExpensesDaily");
transaction.addToBackStack(null);
transaction.commit();
break;
default:
break;
}
}
So using the code above, I opened an instance of MenuExpensesDaily. And inside MenuExpensesDaily, when I click on a menu item, it would open another fragment, ExpensesDailyAdd, as shown below:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_main, menu);
MenuItem mItem = menu.findItem(R.id.tbAddExpenses);
mItem.setVisible(true);
mItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
ExpensesDailyAdd addExpenses = new ExpensesDailyAdd();
getFragmentManager().beginTransaction()
.replace(R.id.container, addExpenses, null)
.addToBackStack(null)
.commit();
return true;
}
});
}
Ok so now when ExpensesDailyAdd is opened, the hamburger icon is changed to the up caret. But when I click the up caret, it opens the drawer instead of going back to the previous fragment.
I am using a DrawerLayout with and adding a new Fragment each time the user taps an item from the drawer menu. This works perfectly.
Within one of those fragments the user can navigate to another fragment:
private void loadArchives() {
PUCNewsArchive news_archive = new PUCNewsArchive();
getFragmentManager()
.beginTransaction()
.add(R.id.container_frame, news_archive, "news_archives")
.addToBackStack(null)
.commit();
}
This will correctly add another fragment to the stack. BUT, it does not change the action bar drawer button/icon to a back button. So, in tapping that just opens the drawer again, which is should not do. The only way to navigate back is the use the hardware back button which does go back to the previous fragment. I tried adding the following to my main Activity to see what was going on:
#Override
public void onBackPressed(){
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
Log.i("MainActivity", "popping backstack");
fm.popBackStack();
} else {
Log.i("MainActivity", "nothing on backstack, calling super");
super.onBackPressed();
}
}
But that is only ever called when I use the hardware back button, as the drawer button is only ever opening the drawer.
I assume this should be checking to see if it should open the drawer or navigate:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
switch(item.getItemId()) {
case android.R.id.home:
return true;
default:
return super.onOptionsItemSelected(item);
}
}
What have I missed? Why is the drawer button never changing to a back button nor acting like one?
You don't need to use the onBackPressed().
I had a very similar situation in my app. Here is how I got it to work:
I created a method in the main activity:
public void foo(int fragment_id) {
if(fragment_id == some_id){
// keep the drawer carat
mDrawerToggle.setDrawerIndicatorEnabled(true);
}else{
// Disable the drawer carat, and enable the back button
mDrawerToggle.setDrawerIndicatorEnabled(false);
getActionBar().setDisplayHomeAsUpEnabled(true);
}
}
I call this method from onResume() of each fragment, and pass it that particular fragments id. Alternatively, you can call it from the loadFragment()/loadArchives() method in your main activity. This works fine for me.
In your Navigation Activity
This activity controls all fragments in the app.
When preparing new fragments to replace others, I set the DrawerToggle
setDrawerIndicatorEnabled(false) like this:
private void loadArchives() {
PUCNewsArchive news_archive = new PUCNewsArchive();
//disable the toggle menu and show up carat
theDrawerToggle.setDrawerIndicatorEnabled(false);
getFragmentManager()
.beginTransaction()
.add(R.id.container_frame, news_archive, "news_archives")
.addToBackStack(null)
.commit();
}
in onCreateview of another fragment
call
// update the actionbar to show the up carat/affordance
getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
For More reference Check This Question
I tried above suggested codes But the "up" or "Back" arrow in left side of action bar was just not showing up in my app. But luckily I was able to fix that.
Brief code:
Function to start fragment while putting the current fragment to Back Stack:
public void startFragment(){
MyFrag myFrag = new MyFrag();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frag_container ,myFrag)
.addToBackStack(null)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.commit();
}
Function to turn ON or OFF "NavigationDrawer":
public void setNavigationDrawerState(boolean isEnabled) {
if ( isEnabled ) {
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
toggle.setDrawerIndicatorEnabled(true);
toggle.syncState();
}
else {
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
toggle.setDrawerIndicatorEnabled(false);
toggle.setHomeAsUpIndicator(R.drawable.ic_keyboard_backspace_white_24dp);
toggle.syncState();
}
I downloaded the drawable: ic_keyboard_backspace_white_24dp from Material.io
The complete answer:
Disabling navigation drawer, toggling home-button/up-indicator in fragments