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
Related
I've been researching a solution to my problem but not a single result fixes my problem.
I have five Java activities. Each activity has five buttons, four to the other activities and one to itself. It's basically just a bar of bottoms at the bottom of the page.
My issue is that let's say I'm in one activity, and then I click that button to the activity again, it opens and loads an entirely new activity. And then when I click back, it shows the previous activity open as I left it. But if I press it ten times, I need to click back ten times. Also, if I switch between each activity twice and I want to click back to main to exit, I need to click back ten times instead of five.
I want it to be such that when I click a button, it opens the activity. If I press the button again, it does nothing if I'm in that activity. And if I'm switching between activities and I repress an activity I already opened, I want that to be brought to the top of the stack from its lower location, not added. So at most, I only want five activities running.
It's a very confusing problem as I see people suggesting to use intent flags, which I'm not sure if I place them in the manifest, which does nothing with I try. And I've seen people suggest using LaunchMode single instance, which also does nothing.
I really think fragments are the best method here. And yes, it's a little tricky but you can use fragments within fragments. For navigating without creating extra instances, I think you might be looking for something along the lines of this:
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if(id == R.id.nav_home){
Fragment newFragment;
FragmentManager fragmentManager = getSupportFragmentManager();
// Look for fragment by tag
Fragment foundFragment = fragmentManager.findFragmentByTag(MAIN_FRAGMENT);
if(foundFragment != null) { //if fragment's already in the backstack
newFragment = foundFragment; //replace fragment with backstack fragment
}else{
newFragment = new MainFragment(); // use a new fragment instance
}
// Add new fragment instance to fragment manager
fragmentManager.beginTransaction()
.replace(R.id.fragment_container, newFragment, MAIN_FRAGMENT)
.addToBackStack(MAIN_FRAGMENT)
.commit();
}
// ...
}
I've had a search on SO and can't find anything that works.
Here's what I want to do, when I navigate between navigation drawer pages, I want the view to be the same. So if I go from page A to B, and then from B to A. I expect A to have the same state.
In my app, I add some text to fragment A via some button. When I navigate to fragment B, and then back to A, the text is gone. I want the text to still be there.
How do I do this?
I've already tried setRetainState(true). This doesn't work. I have also made sure that new Fragment() is only called once when going to the page. This also doesn't work.
The structure of my navigation drawer is identical to the one shown in the Android documentation.
I think, if you have a navigation drawer that you use fragments for each page.
On select item in navigation drawer don't recreate the fragment, just pop it from back stack if it exists.
HomeFragment homeFragment = (HomeFragment) fm.findFragmentByTag(fragmentName);
if (homeFragment == null) {
homeFragment = new HomeFragment();
fm.beginTransaction().addToBackStack(fragmentName).replace(R.id.content_frame, homeFragment, fragmentName).commit();
} else {
fm.popBackStackImmediate(fragmentName, 0);
}
Im trying to Solve a problem where when a user press back key, the fragment should be recreated rather than loading from back stack. I have a single Main activity with a frame layout and i replace the fragments within the single frame dynamically. the code below works when the user go from fragment within fragment. but when the user select from navigation drawer, the replaced fragment is going on to the top of backstack which is causing problems.
Right now the code i wrote in BackKey Pressed Event
public override void OnBackPressed()
{
Android.Support.V4.App.FragmentManager.IBackStackEntry entry =
SupportFragmentManager.GetBackStackEntryAt(SupportFragmentManager.BackStackEntryCount - 1);
string str = entry.Name;
if (SupportFragmentManager.BackStackEntryCount == 0)
{
this.Finish();
}
else
{
Fragment fr = (Fragment)MagicallyCreateInstance(str);
SupportFragmentManager.BeginTransaction().Replace(Resource.Id.content_frame, fr).Commit();
SupportFragmentManager.PopBackStack();
}
base.OnBackPressed();
}
i also have a replace fragment method which i use to replace fragments. but in this process the back key is getting disabled by default somehow (Not sure how) but whenever there is existing fragment in the backstack, the old UI is getting loaded. Can i refresh the layout here?
public void ReplaceFragment(Fragment fragment, FragmentManager fragmentManager)
{
string backStateName = fragment.Class.SimpleName;
bool fragmentPopped = fragmentManager.PopBackStackImmediate(backStateName, 0);
if (!fragmentPopped && fragmentManager.FindFragmentByTag(backStateName) == null)
{
fragmentManager.BeginTransaction()
.Replace(Resource.Id.content_frame, fragment).SetTransitionStyle(FragmentTransaction.TransitFragmentFade)
.AddToBackStack(backStateName)
.Commit();
}
}
Can anyone please help me solve this any one of the above?
I hope I'm understanding your problem correctly. But it sounds like you want to make sure that when the user selects a destination from your main navigation you want to make sure the back stack is cleared or reset.
Ex:
Stack looks like this:
A->B->C
User selects D from main navigation, stack should look like:
D
NOT
A->B->C->D
If this is the case, you should clear the back stack before navigating to any top-level destinations. This can be done like so:
FragmentManager.PopBackStack(null, FragmentManager.PopBackStackInclusive);
The documentation for this method is not great, but it will pop everything off the back stack. A discussion can be found here: https://groups.google.com/d/msg/android-developers/0qXCA9rW7EI/M9riRM0kl9QJ
I have an ActionBar activity. In this activity I have implemented Navigation Drawer from Android API.
One option of navigation drawer set a ListFragment with some elements inside its list.
When I click some elements I want to create a new fragment and set previous ListFragment to the stack. Also I want to destroy this new fragment by clicking ActionBar home button, in order to return to the previous ListFragment.
My problem comes here: When I click home button of the actionbar, drawer layout is displayed, instead of destroy the fragment... What should I do?
I have Overriden onOptionsItemSelected method in the fragment:
#Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case android.R.id.home:
getFragmentManager()
.popBackStack();
}
return (super.onOptionsItemSelected(menuItem));
}
Also I have set ListFragment to the backstack when Inflating the new fragment:
getFragmentManager()
.beginTransaction()
.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right)
.replace(R.id.activity_main_fragment_container, fragment)
.addToBackStack(null)
.commit();
Well, as the docs say here, popBackStack() is async. I suppose that the drawer layout is displayed because you call super.onOptionsItemSelected(menuItem).
I suggest you to return true for all cases you handle this selection by yourself (in this specific situation: case android.R.id.home:), and call getActivity().onBackPressed() (assuming that by pressing hardware back button the last fragment gets removed, as it should) instead of popping back stack directly. I've implemented a similar solution and it works for me.
I created a sample app to test this overlapping issue.
I have a fragment type, Fragment1, and I create a new instance of Fragment1 and add it to a FrameLayout in my activity at runtime. I add the fragment with the help of a few buttons.
Note: I have given each new instance of Fragment1 a different number(#1, #2, #3, etc.) to display on the UI to help me figure out which fragment I am viewing.
So.. here is what I do:
Click on Button 3, create new instance of Fragment1 and add it to Frame1.
Click on Button 4, create new instance of Fragment1 and add it to Frame1 and add it to the fragment backstack.
Repeat 1 and 2.
Repeat 1 and 2.
Now, I have fragments in this order: 1(#1),2(#2),1(#3),2(#4),1(#5),2(#6).
I press the back key when viewing fragment #6.
Back key press, UI displays (#5).
Back key press, UI displays (#3 AND #5),
Back key press, UI displays (#1, #3, AND #5)
It seems fragments are getting displayed ON TOP of each other.
WHY? Is there an overlapping issue? How can I clear out this overlapping issue. I thought this would be an issue on the compatibility library... but it is also on 3.0.
Code for adding fragments:
public int doFragmentChange(int cont1, Fragment frag1, String tag1, int cont2, Fragment frag2, String tag2,
boolean addToStack, String stackTag) {
FragmentManager fm = getFragmentManager();// getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if (frag1 != null) {
ft.replace(cont1, frag1, tag1);
}
if (frag2 != null) {
ft.replace(cont2, frag2, tag2);
}
// add fragment to stack
if (addToStack)
ft.addToBackStack(stackTag);
return ft.commit();
}
If you perform two add calls one after the other (two commit calls) then yes the fragments will appear overlaid, one on top of the other effectively.
So (for new example) if say you replace frag1 with frag2 and then frag3 with frag4 in the same frame with no backstack transaction then I would expect frag2 and frag4 to be overlaid.
Furtheremore there is also a potential issue in your chaining of replace. You should call a separate commit for each. See Android — Replace Fragment Back Stack With New Stack?.
Just override the onBackPress() or onKeyUp and remove the top fragment.