Multiple taps on bottom navigation bar does not happens as expected
bottom bar has 5 tabs
every tab selection pops the tag and pushes the tag
tap on Fragment A--> tap on Fragment B, repeat the same to two to five times.
ex:
Tap A
--> Pops A from stack
--> push A to Stack
Tap B
--> pop B from Stack
--> push B to stack
behaviour:
by default A fragment is loaded, on tap of B navigating to B, later tap on A goes to A, here when back presses app closed.
expected :
result should be something like this
by default A fragment is loaded, on tap of B navigating to B, later tap on A goes to A, here when back pressed it should go to B and backpress goto A then backpress close the app.
case FragmentA:
fragmenta = new FragmentA();
getSupportFragmentManager().popBackStack(FragmentReferenceTags.FragmentA, FragmentManager.POP_BACK_STACK_INCLUSIVE); // returns False - can't find the tag!
transaction.add(R.id.fragment_container_layout, fragmenta, FragmentReferenceTags.FragmentA);
transaction.addToBackStack(FragmentReferenceTags.FragmentA);
transaction.commit();
hideSubTabs();
break;
case FragmentB:
fragmentb = new FragmentB();
getSupportFragmentManager().popBackStack(FragmentReferenceTags.FragmentB, FragmentManager.POP_BACK_STACK_INCLUSIVE); // returns False - can't find the tag!
transaction.add(R.id.fragment_container_layout, fragmentb, FragmentReferenceTags.FragmentB);
transaction.addToBackStack(FragmentReferenceTags.FragmentB);
transaction.commit();
hideSubTabs();
break;
Use replace instead of add :
transaction.replace(R.id.fragment_container_layout, fragmentb, FragmentReferenceTags.FragmentB);
transaction.addToBackStack(null);
Related
According to I have an Activity which contains ViewPager which loads three fragments:
RootA
RootB
RootC
RootA loads another fragment which named as FragA.
RootB loads another fragment which named as FragB.
RootC loads another fragment which named as FragC.
FragmentTransaction fragTransaction = getFragmentManager().beginTransaction();
fragTransaction.replace(R.id.container, new FragA());
fragTransaction.commit();
FragA has a button named as ButtonA to load FragAA.
FragB has a button named as ButtonB to load FragBB.
FragC has a button named as ButtonC to load FragCC.
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragTransaction = fragmentManager.beginTransaction();
fragTransaction.replace(R.id.container, new FragAA, "FragAA");
fragTransaction.addToBackStack("FragAA");
fragTransaction.commit();
I run my App and in the first tab, I press ButtonA. FragAA will be shown. Now I swipe to the second tab and press ButtonB and go to FragBB and then I swipe to the third tab and press ButtonC and go to FragCC.
After that, I swipe to the second tab and then I swipe to the first tab again without any clicking. then I press Back Button. By the first back pressing FragCC will be closed (will put out of BackStack), by the second back pressing FragBB will be closed, and by the third back pressing FragAA will be closed.
But I want my app to close child of current tab not to close fragments according to the BackStack.
I mean the Back Button should close FragAA because I am in the first tab and I pressed Back Button in the first tab!
How can I do it?
I have one activity, ActivityA, and 3 fragments, FragmentA, FragmentB, and FragmentC.
To add FragmentA, I use replace, where fragment is a new instance of FragmentA:
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frame_layout_fragment, fragment)
.commit();
In the onCreate method of ActivityA, I do a check for FragmentA creation:
if (savedInstanceState == null) {
FragmentA fragmentA = FragmentA.newInstance();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frame_layout_fragment, fragmentA)
.commit();
}
To add FragmentB and FragmentC, I use add and addToBackStack, where fragment is either a new instance of FragmentB or FragmentC:
getSupportFragmentManager()
.beginTransaction()
.add(R.id.frame_layout_fragment, fragment)
.addToBackStack(null)
.commit();
I press the back button while on FragmentC, it shows FragmentB, and pressing the back button while on FragmentB shows FragmentA, as expected. While I was on FragmentC, I rotate the device, and FragmentC still shows, as expected.
However, when I navigate from FragmentC to FragmentA using the 2 presses of the back button, then rotate the device twice, portrait -> landscape -> portrait, add FragmentB, add FragmentC, then I rotate the device once, I expected FragmentC to show, but instead FragmentB shows. When I press the back button once, nothing happens. When I press it again, it navigates back to FragmentA. It seems like FragmentC is present in the back stack, but for some reason its not visible.
Why is FragmentC not visible in this scenario?
I think this answer to another question is your answer too: Difference between add(), replace(), and addToBackStack()
It says:
One more importance difference between add and replace is: replace
removes the existing fragment and adds a new fragment. This means when
you press back button the fragment that got replaced will be created
with its onCreateView being invoked. Whereas add retains the existing
fragments and adds a new fragment that means existing fragment will be
active and they wont be in 'paused' state hence when a back button is
pressed onCreateView is not called for the existing fragment(the
fragment which was there before new fragment was added). In terms of
fragment's life cycle events onPause, onResume, onCreateView and other
life cycle events will be invoked in case of replace but they wont be
invoked in case of add.
I have an app with a main activity which loads a navigation drawer, and a pair of fragments that load in that activity ...
In the navigation drawer I have 4 options A, B, C and D ... the first one loads FragmentA on my activity and the last 3 load FragmentB ..
FragmentA displays a list of elements and, upon selecting one of these elements FragmentB is used to load its content... I want to change the home (hamburger/drawer) icon on FragmentB for the up icon when initiating from FragmentA (and change the corresponding behavior to make a popstack on select).. I have no problem with this using setDisplayHomeAsUpEnabled(true), but since all this is occurring inside one activity if I then select one other option (say B) from the navigation drawer the up icon will still be showing (it its also showing on the popped fragment)...
if I use setDisplayHomeAsUpEnabled(false) all this do is hide the home/up button from the toolbar, I need to recover the home button and make sure this will be shown when FragmentB is initiated from the drawer menu ...
Does this problem ring a bell to anyone? or am I just using fragments the wrong way? .. any advice will be appreciated
EDIT
this is more or less what I have in code
In Main Activity .. as the onNavigationItemSelected(MenuItem item) for the drawer I have a something like this ...
switch(optionNumber) {
case 0:
fragment = FragmentA.newInstance(optionNumber);
break;
default:
fragment = FragmentB.newInstance(optionNumber);
break;
}
Fragment frag = fragmentManager.findFragmentByTag("current_fragment");
if (frag != null && frag.getClass() == FolderFragment.class){
((FolderFragment)frag).resetScroll();
}
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentManager.beginTransaction().replace(R.id.content, fragment, "current_fragment").commit();
which selects the fragment to load according to the option selected..
In FragmentA I'm calling FragmentB with this ..
FragmentB fFragment = FragmentB.newInstance(position);
Bundle args = new Bundle();
args.putString("filter", "something"); fFragment.setArguments(args);
mActivity.getSupportFragmentManager().beginTransaction()
.replace(R.id.flContent, fFragment, "current_fragment")
.addToBackStack(null)
.commit();
Preserving the fragment in the stack
And in fragmentB inside onResume() function I got something like...
String filter = getArguments().getString("filter", null);
if (type != null) {
mActivity.setTitle(title);
mActivity.getSupportActionBar().setDisplayShowHomeEnabled(true);
}else {
/*mActivity.getSupportActionBar().setDisplayHomeAsUpEnabled(false);
mActivity.getSupportActionBar().setDisplayShowHomeEnabled(true);
mActivity.getSupportActionBar().setHomeButtonEnabled(true);
mActivity.getSupportActionBar().setIcon(R.mipmap.ic_menu);*/
}
So When I'm creating fragmentB I check for arguments and see if it comes from fragmentA or not ( I could also check the fragmentmanager backstack and see if there's something)... there I just change the drawer icon with setDisplayShowHomeEnabled(true) ... leaving the back arrow, if I return to FragmentA (via onBackPressed()) FragmentA shows the arrow and I need it to show the original drawer icon ... the same happens if I select an option from the drawer menu ...
Does this gives more clarity to my issue ?... I have some commented code there because it doesn't work .. if I activate the line with setDisplayHomeAsUpEnabled(false).. the icon just disappears from the activity (which is the intended result of the function as far as I know)...
After a while I finally found this post
Switching between Android Navigation Drawer image and Up caret when using fragments
I guess that when involving a Drawer in the interface you might need to handle this issue with that component... this post gave me the answer.
Particular notice to the last comment by Wolfram Rittmeyer
I'm working on an inherited Android project that makes use of fragments. The mainactivity has a side menu drawer that allows the user to tap on a list of items, each of which opens a new fragment in another file.
Right now, pressing the back button closes the app abruptly. I wish for the back button to work such that it will bring the user back to the previously viewed fragment, and when the user is at the very first viewed fragment, pressing a back button will bring an app exit confirmation box.
I understand that I should be using addToBackStack() but I'm not sure how to implement it in my code.
Here's the code originally in mainactivity when an item is selected:
FragmentManager fm = getFragmentManager();
switch (position) {
case 0:
if (fragmentManager.findFragmentById(R.id.content_frame != null) {
Fragment currentFragment = fragmentManager.findFragmentById(R.id.content_frame);
fm.befineTransaction().remove(currentFragment).commit();
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
Item0 item1Fragment = new Item0();
fm.beginTransaction().replace(R.id.content_frame, item0Fragment).commit();
break;
case 1 onwards are identical, except Item0/item0Fragment references are replaced with their respective values.
I'm very new to fragments, but from what I can see, the code is first detecting if the activity has a frame for the fragment, and if so, it removes the current fragment, and completely clears the fragment back stack. It then creates a new fragment, and replaces the current fragment with the new one.
Here's my code currently after some changes, and it seems to work, except for a few problems which I'll describe after the code:
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
switch (position) {
case 0:
Item0 item1Fragment = new Item0();
ft.replace(R.id.content_frame, item0Fragment).addToBackStack(null).commit();
break;
The above modified code provides correct navigation, except:
When the I've gone back to the very first fragment, then a back button press removes that fragment and presents an empty fragment on screen, and the next back button press will close the app. The desired behavior would be that a back button press on the very first fragment will bring out a confirmation button to close the app.
When the items on the side menu are tapped and selected, I call mItemList.setItemChecked(position). How do I call update this when the back button is tapped so that the previous selection is selected?
Does anyone know how to make this work?
Thanks.
Have you checked the developer.android ? Here is how they explain.
http://developer.android.com/training/implementing-navigation/temporal.html#back-fragments
Activity 1 is visible. Press a button, and Activity 2 opens.
Activity 2 adds fragment A to itself (and back stack) and it displays fine
Pressing a button within the fragment transitions to another fragment, B
Press Back. Nothing happens. Huh? The Back press is seemingly absorbed and not acted upon, the display remains the same.
Press Back a second time, it reverts to the Activity 1, as expected.
Why is my fragment not being shown in step 4? I've added the fragment to the back stack, so why (when the Back button seems aware of its existence) does it not show the fragment?
Here's the code I'm using in Activity 2 to open Fragment A.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_profile_edit);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
transaction.addToBackStack(null);
transaction.add(android.R.id.content, new MyFragment());
transaction.commit();
}
And here's the code to open Fragment B
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
transaction.add(android.R.id.content, new MyOtherFragment());
transaction.commit();
Have you tried transaction.replace(...) instead of transaction.add(...)? That should work. I'm guessing because if you're just adding a fragment over another, it doesn't see transaction as wanting to go back fro Fragment A.
EDIT
The actual answer for the question is below in the comments: addToBackStack() should be used on the fragment which is replacing, not the one being replaced.