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.
Related
In my application I created a Navigation Drawer which has 5 items, once an item is clicked in the Navigation Drawer, I can correctly check the item and show the new fragment using the fragment manager.
But currently I have three problems:
My application has floating action buttons, that of course perform actions and open new fragments, so I need to handle that "Fragment changing" in the navigation drawer too, setting as checked the current item which corresponds to the fragment showed.
I SORT OF solved this problem, but using a single method that
performs the fragment transaction in the MainActivity and meanwhile
checks the new item. So everytime a Fragment want to call another
Fragment, it uses this function passing the nav_drawer_item_id as a
parameter. I think that this solutions sucks, so if you have a better idea, it would be really welcome!
My biggest problem is that when the user press the Android Back Button, the fragment pops back to previous one (or sometimes I call popback() programmatically because I am done with that specific fragment )
I really don't know how to solve this problem because I can't check the correct item in the navigation drawer once a fragment is popped back, I need to know which fragment it is.
I need to show the new fragment once the navigation drawer is closed in order to respect "Android Rules" ( And because it's nice ).
I sort of solved this problem too, by setting a "nextFragment" inside the navigation drawer onNavigationItemSelectedListener and by showing the new fragment inside the drawer onDrawerClosed. Is it the only solution?
I'm not posting any code because it really doesn't deserve to be seen, so here is some extra info:
I have a single activity which contains the Navigation Drawer and currently handles the fragment transactions.
I have 6 fragments, 5 called from the Navigation Drawer and 1 called only from others UI components, but this one doesn't need to be checked on the drawer of course.
I tought about a solution and it was like "Setting the checked item FROM the fragment that is showed", but I didn't find any way to get the Navigation Drawer from the Fragment in order to set the proper item checked.
Implement FragmentManager.OnBackStackChangedListener in your activity to get notified whenever something is popped off the back stack and sync the navigation drawer from the callback. That should get rid of the problem caused when the back button is pressed.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
.....
getSupportFragmentManager().addOnBackStackChangedListener(this);
}
#Override
public void onBackStackChanged() {
// Get the currently active fragment
Fragment fragment =
getSupportFragmentManager().findFragmentById(R.id.fragments_frame);
// Check which fragment is active, check the
// correct selection and set the title accordingly
if (fragment instanceof FragmentAtPosition0) {
setCheckedAndTitle(0);
} else if (fragment instanceof FragmentAtPosition1) {
setCheckedAndTitle(1);
}
}
private void setCheckedAndTitle(int position) {
MenuItem item = navView.getMenu().getItem(position);
item.setChecked(true);
setTitle(item.getTitle());
}
As for the other two cases that you mentioned, I think the solutions you have mentioned are the preferred ways.
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've got a navigation drawer. In that navigation drawer I've got five fragments. When I select a fragment, it shows up. When I press the back button, it goes to the previous fragment. However, I need the back button to send you back to the first fragment. How do I do this?
Overwrite the onBackPressed() method in your Activity:
#Override
public void onBackPressed(){
FragmentTransactionn ft = getFragmentManager().beginTransaction();
ft.replace([your fragment container], yourfirstFragment, TAG_FRAGMENTFIRST);
ft.commit();
}
Apparently you already figured out how to show fragments. I'd suggest using the same code you use in your navigation drawer in the public void onBackPressed() to draw up the first fragment again. To make users able to exit the app, check if the first fragment is already visible. If so, call super.onBackPressed() or finish().
i have 2 activity Activity-1 and Activity-2 ..... Activity-2 has fragments fragment-1 and fragment-2 and fragment-3 The work flow is.. Activity 1 ---> Activity 2---> fragment 1 ---> fragment 2 ---> fragment --->3 but i am trying back the following sequence.. fragment 3 ---> fragment 2 ---> fragment --->1 Activity 2 ---> Activity 1
i have used
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
it shows an back button left of the ActionBarActivity
i can get the click event here...
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
//do your own thing here
return true;
default: return super.onOptionsItemSelected(item);
}
}
what should i do ?????
When applying your fragment transactions, you need to make sure they are added to the fragment back stack with the addToBackStack() method. Then the framework will do the work of unwinding the fragments before finishing the host activity.
You can read more in the Fragments Developer Guide.
popBackStack and addToBackStack methods will do. See links for details:
How to resume Fragment from BackStack if exists
http://developer.android.com/training/implementing-navigation/temporal.html
You need to use addtoBackStack to add a fragment to backstack, for activity that will be done by default and not for fragments. See the video in the following link. You will get the complete picture:
https://www.youtube.com/watch?v=ZbKKxYUOH-c&list=PLonJJ3BVjZW4lMlpHgL7UNQSGMERcDzHo
I've been researching all day/night for a solution, but it seems there are lots of options to go from an Activity to a Fragment, but none are working for me on S.O. In practice, I am in an Activity, and I want to use my app logo in the ActionBar to click it and then return to a Fragment. This Fragment is the "parent class" of my Activity, meaning there was a button in the Fragment I clicked that took me to my Activity.
But I can't get all the code snippets I've seen to work.
I have put this in my onCreate() of my Activity:
// Shows the up carat near app icon in ActionBar
getSupportActionBar().setDisplayUseLogoEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
I also included this in my onOptionsItemSelected() method of my Activity:
// Handle action bar actions click
switch (item.getItemId()) {
case android.R.id.home:
android.app.FragmentManager fm= getFragmentManager();
fm.popBackStack();
return true;
default:
return super.onOptionsItemSelected(item);
}
The result is that I see a "back button" carat (as shown below), but when I click it nothing happens. I'm supposed to go back to the Fragment I came from. FYI, my Fragment class actually extends Fragment (not FragmentActivity). My Activity extends ActionBarActivity, so I am looking for an answer that will work for Android 4.0+. Also, my Fragment does not need the same instance (necessarily) when it is returned to. It only has buttons on there, so a new instance is fine, if it gets created, upon returning.
Thanks for your help!!
One small line was needed: finish(). Since the FragmentManager pops off one item in its backstack, by using fm.popBackStack();, it still needs some sort of action to go to the previous fragment. Adding finish() enabled the current Activity to end. The line in context:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar actions click
switch (item.getItemId()) {
case android.R.id.home:
android.app.FragmentManager fm= getFragmentManager();
fm.popBackStack();
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
The rest of the code I had above was correct and is needed too, to make it all work. Now, I am able to navigate to my NavigationDrawer fragment, click a button there to go to an Activity, then press the navigation UP caret to return to my Fragment at anytime. This was tested successfully on a Samsung Galaxy5 phone.
One thing that you do not read about in the Navigating Up with the App Icon section of the ActionBar Android doc is that since you are using a fragment to return to, you cannot use their <meta-data> tag instruction to specify the parent activity in the manifest file, because you are not returning to an Activity! But rather a Fragment. So a workaround had to be achieved by using FragmentManager.