I have the MainActivity, it contains ListFragment and framelayout, I am able to change the fragments on list on item click.
I have a problem to replace the existing Fragment1 with the new Fragment2, on button click of Fragment1, Fragment2 should replace the Fragment1, and should have the same ListFragment at left, and back buttons should be properly handled,this means when I am in Fragment2 and press back button it should show the same ListFragment and Fragment1.
You need to use .replace to switch the two fragments, you also need add add the original to the backstack so you can recall it, and you need to override the back key operation to function that way. It would look something like this (using code from one of my projects, using the support library):
To show your first fragment:
menu = new MenuFragment_Main(); // instantiate fragment
getSupportFragmentManager().beginTransaction().replace(R.id.pane, menu).commit(); // display fragment
To swap it for the new fragment and add it to the backstack:
ListFragment_ShopListItem shoplist = new ListFragment_ShopListItem(); // instantiate fragment
getSupportFragmentManager().beginTransaction().replace(R.id.pane, shoplist).addToBackStack(null).commit(); // replace original fragment with new fragment, add original to backstack
And to override the back key to go back to the previous fragment:
public void onBackPressed() {
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.popBackStack();
return;
}
Related
I replace Fragment-A with Fragment-B, and on calling popbackstack() in Fragment-B i will redirect back to Fragment-A. So I wanted to call a method that will update the list.
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.
In Short for your use case, you need to use add and if you don't want the fragment views to overlap then you might replace the Fragment B view background color with a solid color instead of transparent.
When you add your fragment, you also have to add it to your fragment's backstack.
FragmentTransaction ft = getSupportFragmentManager.beginTransaction();
ft.replace(R.id.content, fragment, backStateName);
ft.addToBackStack(backStateName);
ft.commit();
(here R.id.content is your fragment container in your activity)
Then you have to override onBackPressed method in your activity that contains your fragments.
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 1) {
getSupportFragmentManager().popBackStack();
}
}
if you want to customize your onBackPressed then you can check for your currently visible fragment in your activity and create a callback for performing action for that particular fragment. example -
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 1) {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.content);
if (fragment instanceof FragmentB) {
((FragmentB) fragment).onBackPressed();
// getSupportFragmentManager().popBackStack();
}
}
now you can add getSupportFragmentManager().popBackStack(); in your Fragment's onBackPressed() method.
Imagine i have main activity that has viewpager. I have 2 fragments called (F1 & F2) that will transaction into viewpager.
Again imagine in F1 fragment i want to set a button. When clicking on button, i want to transaction other fragment call SUBF1 but not into F1 fragment.
My question is here!!! Is it possible to replace SUBF1 with it's parent means F1?My idea is that i want to replace sub fragment with it's parent fragment that has been kept on fragment's container in main activity?
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.details, new NewFragmentToReplace(), "NewFragmentTag");
ft.commit();
You can save the instance of current fragment, when you are
navigating from one fragment to other. When user press the back
button, you can open the specific fragment with the help of tag.
#Override
public void onBackPressed() {
String currentTag = currentFragment.getTag();
if(currentTag.equals(res.getString(R.string.fragmentTagTest)))
{
currentFragment = AnotherFragment;
replaceFragment() // integrate replace current fragment with new one.
}
}
I have a two pane layout.
I have a fragment on the left and a fragment on the right. Now I want to replace the left with the one on the right and create a new one on the right (i.e. I want to move the one on the right to the left, and create a new one on the right):
private FragmentManager fm; // assigned in onCreate
private MyListFragment rightSide; // assigned in onCreate
public void onClicked(Fragment fragment) { // callback
fm.beginTransaction().replace(R.id.left_side, rightSide).commit();
leftSide = rightSide;
rightSide = MyListFragment.newInstance();
fm.beginTransaction().replace(R.id.right_side, rightSide).commit();
}
Now at this point I get a IllegalStateException:
java.lang.IllegalStateException: Can't change container ID of fragment MyListFragment{300c6aae #1 id=0x7f070094}: was 2131165332 now 2131165331
Well I can circumvent this situation by
fm.popBackStackImmediate(null, fm.POP_BACK_STACK_INCLUSIVE);
fm.beginTransaction().remove(rightSide).commit();
fm.executePendingTransactions();
But I also want to have the ability to add it to the back stack. When I press back I would like to remove the one on the right and move the one from the left back to the right.
How can I make one transaction out of this with the ability to add it to the backstack and revert the transaction?
Do it all in one transaction, then call addToBackStack() to undo the whole thing when you press the back button:
private FragmentManager fm; // assigned in onCreate
private MyListFragment rightSide; // assigned in onCreate
public void onClicked(Fragment fragment) { // callback
MyListFragment newRightSide = MyListFragment.newInstance();
fm.beginTransaction()
.remove(rightSide)
.replace(R.id.left_side, rightSide)
.replace(R.id.right_side, newRightSide)
.addToBackStack(null)
.commit();
}
I know how to add a Fragment to the backstack but how do I know, when the user presses the back Button, which fragment I left and which I went to? I need to do a certain action depending on this so I need to know from and to which fragment I am going. Specifically I need to know which fragment I left so if it is a certain fragment, I can remove a button.
Override onBackPressed in Activity:
#Override
public void onBackPressed(){
FragmentManager fm = getSupportFragmentManager();
Fragment f = fm.findFragmentById(R.id.content_frame); // get the fragment that is currently loaded in placeholder
Object tag = f.getTag();
// do handling with help of tag here
// call super method
super.onBackPressed();
}
You can add the Fragment like this :
ArticleMain articalemain = new ArticleMain();
getFragmentManager().beginTransaction().add(R.id.fragment_Top, articalemain, "MY_FRAGMENT").commit();
While Removing the Fragments do like this :
ArticleMain myFragment = (ArticleMain) getFragmentManager()
.findFragmentByTag("MY_FRAGMENT");
if (myFragment.isVisible()) {
// add your code here
myFragment.getFragmentManager().beginTransaction()
.remove(myFragment).commit();
}
My question is not easy to describe, but I will do my best:
On my tablet-app I have one activity with a listFragment A on left side and a detailFragment B on right side. So when I click an item on the list, the detailFragment shows the proper details of the chosen (list) item.
Now when I click a button on my detailFragment B. the fragment gets swapped with a new Fragment from type infoFragment. The listFragment on left side stays as it is.
So now, when I click another item on the List, I want the infoFragment to vanish and get a detailFragment once again.
My problem is, that i need some kind of check if currently there is an infoFragment or a detailFragment displayed. So that I can either just refresh the detailFragment OR stop the infoFragment and build a new detailFragment.
idea:
if ( //detailFragment is active ) {
updateContent();
}
else {
FragmentManager.buildDetailFragment();
}
have been fiddling for hours now, any help is appreciated!!
How can i figure it out whether there is a detailFragment or listFragment displayed?
edit:
i change my detailFragment with the infoFragment here:
FragmentManager fm = getFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.details_fragment);
fragment = new InfoFragment();
fm.beginTransaction()
.replace(R.id.details_fragment, fragment)
.commit();
When you add a Fragment to your fragment manager with a FragmentTransaction you can specify a key value. You can then findFragmentByTag which will determine if the Fragment with that key value has been added to the fragment manager.
So long as you are not using a ViewPager or some other structure where multple fragments are added at once, searching for whether your fragment manager contains a fragment by tag will let you know which is currently displayed. You can then use the results of that search to update the fragment since the result is a reference to the fragment itself.
This means you can pass data from the FragmentActivity to the fragment directly by calling any publicly accessable fragment methods. For example
Fragment displayedFragment = fragmentManager.findFragmentByTag(TAG);
if(displayedFragment != null){ //null if no fragment with tag value
displayedFragment.updateList() //public method within fragment
}
MyFragment myFragment = (MyFragment)getFragmentManager().findFragmentByTag("MY_FRAGMENT");
if (myFragment.isVisible()) {
// add your code here
}
From Here
FragmentManager fm = getFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.content_id);
now we can get the fragment name by getClass
fragment.getClass().getSimpleName()
You can get class of fragment and check which one it exactly is by calling getClass().