My application contains AppBaseActivity having NavigationView with few menu items. By default, I load Home fragment & on clicking each menu item from drawer, I open specific fragment.
My problem is, I need keep Home fragment all the time showing if user clicks back button.
Stepwise explanation :
On activity launch, loads Home fragment by default
Suppose selects Menu Item 1, loads related fragment[*4]
Suppose selects Menu Item 2, loads related fragment[*4]
I want to make back stack clear however, keeping Home fragment persistent so that if user presses back button instead of opting menu item from drawer or simply go to any fragment & on killing it, should navigate back to Home fragment.
In my current case, it simply closes/terminates my app.
AppBaseActivity Java (some part of code)
onCreate() {
fragmentTransaction = fragmentManager.beginTransaction();
HomeFragment homeFragment = new HomeFragment();
fragmentTransaction.add(R.id.body_container, homeFragment, getResources().getString(R.string.app_name));
fragmentTransaction.commit();
}
#SuppressWarnings("StatementWithEmptyBody")
#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 :
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentTransaction = fragmentManager.beginTransaction();
TCFragment tcFragment = new TCFragment();
fragmentTransaction.add(R.id.body_container, tcFragment, getResources().getString(R.string.tc_screen_name));
fragmentTransaction.commit();
break;
case R.id.nav_about_us :
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentTransaction = fragmentManager.beginTransaction();
AboutUsFragment aboutUsFragment = new AboutUsFragment();
fragmentTransaction.add(R.id.body_container, aboutUsFragment, getResources().getString(R.string.about_us_screen_name));
fragmentTransaction.commit();
break;
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
try by adding this line with home fragment before commit:
fragmentTransaction addTobackStack(null);
You need to add the transaction to the backstack using addToBackStack(). The back press would automatically pop the topmost fragment from the backstack.
Refer to
https://developer.android.com/guide/components/fragments.html
The relevant section is "Performing Fragment Transactions"
Related
When I open a fragment from BottomNavigationBar, it opens perfectly. When I press back button, previous fragment opens but state of BottomNavigationBar does not change.
As in my screenshots, when i backpressed from Account fragment, Home fragment opens but state of BottomNavigationBar has not been changed.
Screenshot 1 - https://drive.google.com/file/d/12cDvhwO1jpG2A1PUsfHQGProqx2cT6Bp/view
Screenshot 2 - https://drive.google.com/file/d/1Zws5sMJeXxts6k6IEBGUGyJYfZP58Czs/view
btnNavBar.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.action_item1:
loadFragment(fragmentManager, new HomeFragment(), "Home");
break;
case R.id.action_item2:
loadFragment(fragmentManager, new SearchFragment(), "Search");
break;
case R.id.action_item3:
loadFragment(fragmentManager, new AccountFragment(), "Account");
break;
}
return true;
}
});
public static void loadFragment(FragmentManager fragmentManager, Fragment fragment, String tag) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.frameLayoutContainer, fragment);
fragmentTransaction.commit();
}
I suggest you to not add the fragments to the back stack because it's not the expected behaviour for the Android users. The bottom bar is here to show 3 to 5 different destinations to the user (for example, a news feed, a user profile, etc.). When you select a tab, you should just change the current fragment (and not create a fragments stack). The back button should only close the app, or re-open the previous screen if there is one (definitely not re-open the previous tab :) ). I suggest you to look at this Material Design guidelines for BottomNavigationBar.
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 working with the navigation drawer, and having a small problem. The problem occurs When I am in my an activity, and navigate to that same activity though the navigation drawer. The activity launches new (screen popping up).
I would like the drawer to just close when the user attempts to navigate to the activity they are currently on.
Thanks for you help!
Why not just check the current Activity, pseudocode:
if (this instanceof SomeActivity){
closedrawer();
}else{
navigate to SomeActivity
}
//global reference
private DrawerLayout mDrawerLayout;
//instantiate onCreate()
mDrawerLayout= (DrawerLayout) findViewById(R.id.drawer_layout);
//close it some where, on button click...
if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
mDrawerLayout.closeDrawer(Gravity.LEFT);
}
In the method you handle clicks from the navigation drawer:
// This is for the case where the user is trying to open a fragment called `NewFragment`
Fragment currentFragment = getSupportFragmentManager().findFragmentByTag(NewFragment.TAG);
if (currentFragment == null) {
NewFragment newFragment = new NewFragment()
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment, NewFragment.TAG);
transaction.commit();
}
mDrawerLayout.closeDrawer(mDrawerList);
This works if you have added your fragments to the fragment container with the tag. I usually keep this as a public static final String in the respective fragments. For instance, NewFragment has a static String called TAG that is can be used to find it later using the fragment manager.
If the currentFragment is null, it means that is not currently added to the manager's activity nor on the back stack. In that case add the new fragment to the fragment container. If not, just simply close the navigation drawer.
I've looked around but found no real solution to my particular issue. So I have a navigation main activity, which consists of a navigation drawer and a frame layout for my content.
In my nav drawer are three buttons, each of which fill the frame layout with a specific fragment. One of those fragments acts as a "master view", and clicking on an item in that fragment then opens another fragment which is the "details view".
The problem I am having is this: If I am in the details view fragment, and I click on another button in my nav drawer to go to another fragment, then click on the nav drawer button to get back to my details view then it's fine, I get there ok. When I hit the back button however it takes me back to the previous fragment rather than the master view fragment. Is there any way I can get around this?
Here is a snippet of how I am moving between different fragments in my nav drawer:
private void selectItem(int position)
{
FragmentManager fragmentManager = getFragmentManager();
Fragment fragment = null;
Bundle args = new Bundle();
switch (position)
{
case 0:
fragment = new ReportIt();
fragment.setArguments(args);
break;
case 1:
Fragment f = fragmentManager.findFragmentByTag("article_view");
if (f == null)
{
fragment = new ReadIt();
fragment.setArguments(args);
}
else
{
fragment = f;
}
break;
case 2:
fragment = new FindIt();
fragment.setArguments(args);
break;
default:
fragment = new ReportIt();
fragment.setArguments(args);
break;
}
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment).addToBackStack(null)
.commit();
mDrawerList.setItemChecked(position, true);
setTitle(mNavTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
And my master view fragment passing control to the details fragment:
FragmentManager fragmentManager = getFragmentManager();
Fragment fragment = new ReadItDetail();
Bundle args = new Bundle();
args.putString("ArticleId", pr.GetId());
fragment.setArguments(args);
fragmentManager.beginTransaction().addToBackStack(null)
.replace(R.id.content_frame, fragment, "article_view")
.commit();
So as you can see from the graph, All 3 of the navigation drawer buttons are part of my main activity. Also in my main activity is a framelayout which uses the fragments shown. All boxes outside of the navigation drawer button box are fragments. The master and detail are what I am having issues with. When I move around to other fragments, and then come back to my details fragment, hit the back button, I want it to go back to the master fragment 100% of the time rather than moving back to whatever other fragment I may have been on previously.
To control what Fragment you go back to you just need to control the entries in the backstack. FragmentManager will let let you pop the backstack so you can reset what back does once you navigate to the details fragment. There are a number of posts about this on SO - here's one and here's amonther that provides some more detail.
The one problem with this is that by overriding the natural flow of the back stack you run the risk of creating navigation that does not stem logically from the app. But you know your structure better than the system. If it makes sense to always go from detail to master, go for it.
Ok i have an activity with one main fragment, that has a menu on it. When a user clicks on a menu item another fragment is animated into the screen, with this code:
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.push_left_in, R.anim.push_left_out);
ft.hide(getFragmentManager().findFragmentByTag("menu_fragment"));
Fragment opisFragment = getFragmentManager().findFragmentByTag("opis_fragment");
if (opisFragment == null) {
opisFragment = new OpisFragment();
ft.add(R.id.p_container, opisFragment, "opis_fragment");
ft.commit();
} else {
ft.show(opisFragment);
}
Note: pr_fragment is the tag of the current fragment, the one that has the menu.
Now, this works well, but when i'm on the second fragment i want to add the functionality, that when the user clicks the back button it will show the first fragment. With this code, when i click back it exits the activity alltogether.
Thank you for the help!
All you need is to use addToBackStack(String name) of FragmentTransaction
// Showing menu fragment also added in backstack
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.push_left_in, R.anim.push_left_out)
.add(R.id.p_container, menuFragment, "menu_fragment")
.addToBackStack("menu_fragment")
.commit();
// Showing opis fragment also added in backstack
FragmentTransaction ft2 = getFragmentManager().beginTransaction();
ft2.setCustomAnimations(R.anim.push_left_in, R.anim.push_left_out)
.add(R.id.p_container, opisFragment, "opis_fragment")
.addToBackStack("opis_fragment")
.commit();
Assuming "opis fragment" is in foreground, when you press back button, "menu_fragment" will be displayed back to the foreground, pressing back button again will exit the activity.
With this code, when i click back it exits the activity alltogether.
Normal because there is just your activity in your app stack. the addToBackStack() method is what you are looking for.
if (opisFragment == null) {
opisFragment = new OpisFragment();
ft.add(R.id.p_container, opisFragment, "opis_fragment");
ft.addToBackStack("tag"); // <<< this line
ft.commit();
}
From the doc :
Before you call commit(), however, you might want to call addToBackStack(), in order to add the transaction to a back stack of fragment transactions. This back stack is managed by the activity and allows the user to return to the previous fragment state, by pressing the Back button.
in mainactivity you can check fragments count if fragments count more than one we will show back button
if(getSupportFragmentManager().getBackStackEntryCount() > 0)
{
mDrawerToggle.setDrawerIndicatorEnabled(false);
getSupportActionBar().setDisplayShowHomeEnabled(false);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
else
{
mDrawerToggle.setDrawerIndicatorEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setHomeButtonEnabled(false);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}