I want to play hide animation on back press.
I have working version of code for following packages:
android.support.v4.app.Fragment;
android.support.v4.app.FragmentTransaction;
code is following:
ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_bottom, R.anim.slide_out_right);
Fragment fragment = new RegisterFragment();
ft.replace(R.id.sign_in_fragment, fragment);
ft.commit();
But now I am using androidx packages
androidx.fragment.app.FragmentTransaction;
In which case the back press animation does not work. it just removes fragment constantly.
well code is little different but same:
ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_top, R.anim.slide_out_top, R.anim.slide_out_top, R.anim.slide_out_top);
ft.replace(R.id.menu_fragment, menuFragment);
ft.addToBackStack(null);
ft.commit();
R.id.menu_fragment is empty and I do replace but add has same result.
I found one answer which suggests to add tags on fragments but it does not work.
I think it's androidx package problem and I don't know with what to change.
And project does not let me use just same old this package: android.support.v4.app.FragmentTransaction;
What to do or where do I make mistake?
Thanks in advance.
You can implement animation in the onBackPressed Method of your MainActivity.
override fun onBackPressed() {
val fragment = supportFragmentManager.fragments.last()
supportFragmentManager.beginTransaction().setCustomAnimations(R.anim.slide_up,R.anim.slide_down).remove(fragment).commit()
}
check this code..
My_Fragment fragment = new My_Fragment()
supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.slide_in_right,
android.R.anim.fade_out)
.replace(R.id.container, home_Fragment_admin).commit()
The problem seems to be the remove function which onBackPressed function is using. Because that my R.id.menu_fragment was empty when I added a fragment, the onBackPressed function uses remove method instead of replace or other.
Which lead me to this question.
I found way out from this (which is suggested in the question's answers) but it's ugly.
Basically What I did was create other fragment and Override onBackPressed so instead of remove function I made it replace by other fragment which is fully hidden by the replace animation.
List<Fragment> fragments = getSupportFragmentManager().getFragments();
Fragment fragment = fragments.get(fragments.size() - 1);
getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.slide_out_top, R.anim.slide_out_top).replace(R.id.menu_fragment, exitMenuFragment).commit();
And when entering fragment again I matched animations of enter and exit;
ft.setCustomAnimations(R.anim.slide_in_top, R.anim.slide_in_top);
very poor execution but only I found.
Related
I've done some research but I really couldn't find the answer.
I have single activity with side menu, and holder. I have many (non support) fragments, and all of them are using same holder (one at a time).
When user uses menu (it's in main activity), and goes another page, I want to add name of the current fragment to backstack (using .addToBackStack(Fragment1.class.getName())), but I couldn't find how to get current fragment.
I don't want to implement interface etc to keep track of current fragment. There is a super simple way using fragmentManger isn't there?
You can get your current fragment like this:
if (getFragmentManager().getBackStackEntryCount() > 1) {
Fragment f = getFragmentManager().findFragmentById(R.id.content_frame);
if (f instanceof BlankFragment) {
// Do something
}
}
OK,
If you want to get latest entry from backstack(thanks to #AndroidGeek);
fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount()-1);
and, if you want to get currently active fragment (thanks to #Salman500 #AndroidGeek);
Fragment f = getFragmentManager().findFragmentById(R.id.fragment_holder);
you can use this to get fragment id for non support fragment
Fragment fragment = getFragmentManager().findFragmentById(R.id.fragment_id);
if(fragment!=null)
{
getFragmentManager()
.beginTransaction()
.addToBackStack(null)
.commit();
}
You can keep track of fragments in the main activity (with variables) and access them there. Example:
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction= manager.beginTransaction();
MyFragment myFragment = new MyFragment();
myFragment.doSomething();
Adding to the back-stack:
FragmentTransaction fragment = getSupportFragmentManager().beginTransaction();
fragment.addToBackStack(fragment);
fragment.commit();
This is answered here: get currently displayed fragment
Just use addToBackStack() before you commit() the fragment trancsaction. See it here
So your code will look like :
...
fragmentTransaction.replace(R.id.holder, newFragmentToShow, newFragmentTag);
fragmentTransaction.addToBackStack();
fragmentTransaction.commit();
...
EDIT : after OP was edited
You do not need the fragment class to call addToBackStack() as you have mentioned in the OP. The String argument is an optional string just to keep the state for the backstack state. You should see the documentation
It is all internally managed and the current active fragment is automatically added to the backStack, you may call it from where ever you want, it will always use current active fragment.
I have a bug with replacing fragments inside FrameLayout container.
When app is started first time everything is Ok but when I hide app and then resume it fragments start overlap each other when FragmentTransaction.replace method is called
I've seen almost all stackoverflow questions about such issues but I can't resolve this issue
Code:
<FrameLayout
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
Add initial fragment:
getSupportFragmentManager().beginTransaction()
.add(R.id.frame, RequestFragment.newInstance(), REQUEST_FRAGMENT_TAG)
.commit();
Replace:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
switch (menuItem.getItemId()) {
case R.id.request:
ft.replace(R.id.frame, RequestFragment.newInstance(), REQUEST_FRAGMENT_TAG);
ft.commit();
return true;
case R.id.finished:
ft.replace(R.id.frame, FinishedFragment.newInstance(), FINISHED_FRAGMENT_TAG);
ft.commit();
return true;
case R.id.questions:
ft.replace(R.id.frame, QuestionsFragment.newInstance(), QUESTIONS_FRAGMENT_TAG);
ft.commit();
return true;
default:
return true;
}
Difficult to say as your code provides no context as to when it is run but I suspect the issue is when you are adding your initial fragment.
You are calling add instead of replace which will just add the new fragment on top of any existing ones. It is perfectly fine to use replace even if the container does not yet contain anything.
Fragments survive in the FragmentManager and are automatically re-attached to their container when the Activity restarts. The correct procedure is to check for an existing Fragment before adding a new one.
Add initial fragment
Fragment f=getSupportFragmentManager().findFragmentById(R.id.frame);
if (f==null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame, RequestFragment.newInstance(), REQUEST_FRAGMENT_TAG).commit();
}
Also, it is helpful to make use of logging getSupportFragmentManager().getFragments().size(); whilst you are debugging. It lets you know how many fragments are currently in the FragmentManager and can highlight potential issues in your code. For example, if your count goes up every time you rotate the device, you are adding fragments and not checking for existing ones.
try to use FragmentTransaction.commitAllowingStateLoss() instead of using commit()
This sometimes happens because of the fragment background. Try setting solid background to all fragments in the stack so it's not empty or set to #null.
I wasn't calling the commit method at the end.
I um uzing this code:
FragmentManager FManager = getFragmentManager();
FragmentTransaction FTransaction = FManager.beginTransaction();
FTransaction.setTransitionStyle(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragment.setArguments(fragment.getArguments());
FTransaction.add(ResourceId, fragment, label);
FTransaction.addToBackStack(backStack);
FTransaction.commit();
and I m geting this on my activity:
http://i.stack.imgur.com/K9NKy.png
can someone help me?
I hope that my simple answer will help you. Currently, You are loading an another fragment over your main fragment. you need to "hide" or "remove" or "replace" with old one. As i mentioned them below
In case of Remove or Hide
Fragment fr2 = fragmentManger.findFragmentByTag(Constants.TAG_Detail_Page);
if (fr2 != null)
fragmentTransaction.remove(fr2);
While for "Replace", you will assign new fragment to contentView:
FTransaction .replace(R.id.fragment_container, newFragment);
You are asking the fragment manager to add another fragment and it is doing just that. You never tell it to do anything to the original fragment. If you want to remove the exisitng fragment and show a new one then you should be calling:
FTransaction.replace(...)
instead of calling add.
If the original fragment has been added via the xml layout file, it is more difficult to replace. There are multiple SO questions dealing with that situation.
My project contains two fragment :
FragmentA : the fragment loaded by default when the app starts
FragmentB : replace the fragmentA when a click on a button is done.
This is the XML of my main view :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/main_fragment_container"
android:name="fragmentA"
android:layout_width="match_parent"
android:layout_height="match_parent">
</fragment>
</LinearLayout>
When I wish to replace the FragmentA by the FragmentB, I use this code :
FragmentTransaction fragmentTransaction = getSupportFragmentManager()
.beginTransaction();
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.main_fragment_container, new FragmentB());
fragmentTransaction.commit();
This code works fine. My FragmentA is replaced by the new FragmentB. But when a click is done on the back button, I wish replace the FragmentB by the FragmentA by using popBackStackImmediate().
This is the code I use:
if (getSupportFragmentManager().getBackStackEntryCount() > 0){
boolean done = getFragmentManager().popBackStackImmediate();
fragmentTransaction.commit();
}
The function popBackStackImmediate return always false and the FragmentB still in foreground.
Why the FragmentA does not replace the FragmentB when I call popBackStackImmediate ? Is anybody has an idea to solve my problem?
thanks in advance
You use the getSupportedFragmentManager() to replace FragmentA by FragmentB. But you call popBackStack() on the getFragmentManager().
If you are adding the Fragments to the android.support.v4.app.FragmentManager you also have to call popBackStack() on the same FragmentManager.
This code should solve the problem:
if (getSupportFragmentManager().getBackStackEntryCount() > 0){
boolean done = getSupportFragmentManager().popBackStackImmediate();
}
You should call
fragmentTransaction.addToBackStack(null);
after performing all operations such as add(), remove(), and replace() and Just before commit(). Only then this transaction will be added to backstack. Only then you will be able to return to previous fragment state with Back button. Details here.
The problem is you're mixing Fragment and methods from the support library.
If you are using the support library, make sure:
your Activity extends from the android.support.v4.app.FragmentActivity
your Fragment extends from android.support.v4.app.Fragment
use getSupportFragmentManager() to get the android.support.v4.app.FragmentManager
Your code in the Activity would be:
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStackImmediate();
}
Please be aware that if you would like to get the FragmentManager from the Fragment code, you have to use the getFragmentManager method, as explained in the documentation (probably that's the cause of some confusion if you don't have much experience).
If you are not using the support library:
your Activity extends from the android.app.Activity
your Fragment extends from android.app.Fragment
use getFragmentManager() to get the android.app.FragmentManager
Your code would be:
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStackImmediate();
}
fragmentTransaction.commit(); is not necessary in both cases, so remove it.
Also, please call fragmentTransaction.addToBackStack(null); just before the commit but after the other operations.
I will suggest using the fragment replacement with Tag to produce the same result .
Add the fragment B to activity with tag
fragmentTransaction.replace(R.id.main_fragment_container, new FragmentB(),"TAG_B");
Fragment A -> Fragment B [onBackPressed] -->Fragment A
Override the onBackPressed() in the Activity files where ,
// check for fragment B and you are viewing fragment B
if (getSupportFragmentManager().findFragmentByTag("TAG_B")!=null)
{
fragmentTransaction.replace(R.id.main_fragment_container, new FragmentA(),"TAG_A");
}
addToBackStack("TAG") and popBackStackImmediate("TAG") always revert to fragment condition without any data in the UI right before fragment is created or added to activity !
The problem is in the order of your code. Here are two things you need to pay attention to.
You need to use addToBackStack() after your adding,
replacing fragment. Then commmit()
Then popBackStackImmediate can reverse the operation and it is working. I hope it solves the problem. I know it is an old post but I
do encounter a similar problem and wish this update can help others. Below should be the correct order:
FragmentTransaction fragmentTransaction =getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.main_fragment_container, new FragmentB());
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
If you are Struggling with addToBackStack() and popBackStack() then simply use
FragmentTransaction ft =getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, new HomeFragment(), "Home");
ft.commit();`
In your Activity In OnBackPressed() find out fargment by tag and then do your stuff
Fragment home = getSupportFragmentManager().findFragmentByTag("Home");
if (home instanceof HomeFragment && home.isVisible()) {
// do you stuff
}
For more Information https://github.com/DattaHujare/NavigationDrawer I never use addToBackStack() for handling fragment.
I have an activity with a FrameLayout in it.
The activity should show four steps, and each step is a Fragment. When I want to go back-further, I don't want my fragments to be recreated. I would like to retain them and simply replace their view in my fragment.
I used to first create my Fragments and add them in the backstack like this:
Fragment step= new Frag1ActCompleteFragsCommTrack();
FragmentTransaction ft= getSupportFragmentManager().beginTransaction();
ft.add(step, ""+onStepNr);
ft.addToBackStack(null);
ft.commit();
notice that I don't show it, I simply create it and add to the backstack.
So, once I need one of my fragments to show, I add it (in this example I don't remove any fragment from the framelayout just because it's my first add):
FragmentTransaction ft= getSupportFragmentManager().beginTransaction();
ft.add(R.id.my_frameLayout, step);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
So: the problem is that I obtain a
Caused by: java.lang.IllegalStateException: Fragment already added: Frag1ActCompleteFragsCommTrack{410dcb20 #0 id=0x7f050041 -1}
But I think I can't add directly into my framelayout the first time, otherwise the next time I replace it, I could lose my fragment. Am I right? So.. what's the best practice for retaining fragments that could interchange each other in a framelayout?
Ladies and gentlemen, I did it!
If you add a Fragment, and you want it to be shown in a framelayout, remember to put it in the Fragment backstack. That's it! If you replace it in the framelayout with another one, no worries: you can put it back by finding it thanks to its tag.
It was easier than I thought actually
//step is an int describing the step associated to the fragment I wanna place
FragmentTransaction ft= getSupportFragmentManager().beginTransaction();
ft.replace(R.id.act_complete_track_frameLayout, f, ""+step);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
if(firstAttach)
ft.addToBackStack(null);
ft.commit();
imagine a fragment with tag "1" replaced through the code above by a fragment with tag "2". If I want to go back to step1, I reuse that code by obtaining my old fragment with getSupportFragmentManager().findFragmentByTag("1")
To be short, I thought that FragmentTransaction.replace removed the fragment from the backstack as well. That seems not to be the case (luckily)
You can always do something like fragmentManager.putFragment(yourFragment);
If I understand correctly, you are trying to add all the fragments but not show them until you are ready. FragmentTransaction.add() doesn't exactly do that though. It will also be shown after its added. You should use hide() after adding each fragment, and then later you can use show() to make it visible, and hide() again to make other fragments invisible.
Like this:
Fragment step = new Frag1ActCompleteFragsCommTrack();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(step, ""+onStepNr);
ft.hide(step);
ft.commit();
Then later:
Fragment step = getSupportFragmentManager().findFragmentByTag(""+onStepNr);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.show(step);
// may want to hide other fragments here
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();