I have one activity and multiple fragments in my app. i want to back one by one fragments when pressing back button which in all fragments.
i used this code segment but when pressing back button it comes to main activity without back one by one. Also i want to change the icon when it's comes to the main activity.(msg_alert)
btnBack.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager fm = MainActivity.this
.getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
Fragment fragment = new MainMenuLayout();
ft.replace(R.id.activity_main_content_fragment, fragment);
ft.commit();
btnBack.setVisibility(View.VISIBLE);
btnBack.setImageResource(R.drawable.msg_alert);
tvTitle.setText("Layout 0");
}
});
Lets say you are having two fragments A and B. Fragment A is is attached at the startup of activity and on any user event you navigate to fragment B by replacing the Fragment A.
1) while adding Fragment B to the activity
// Works with either the framework FragmentManager or the
// support package FragmentManager (getSupportFragmentManager).
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fragmentB, "detail")
// Add this transaction to the back stack
.addToBackStack()
.commit();
2) override the onBackPressed of the activity to handle the back button press event.
#override
public void onBackPressed() {
// is there any fragment in backstack, if yes popout.
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
return;
}
super.onBackPressed();
}
this is one more option ,
in the Activity.
Fragment secondfragment= new SecondFragmnet();
#Override
public void onBackPressed() {
if(secondfragment.isVisible()){
// replace 1st fragment
}else{
// Alert dialog for Exit App
}
// you can check multiple fragments.
Hope it helps you
You have to Use addToBackStack() method while doing Transaction Between Fragments...
Read This : Implement Back Navigation for Fragments
Use Following code when you use Fragment Transaction...
String backStateName = fragment.getClass().getName(); // getting Fragment Name..
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment)
.addToBackStack(backStateName) //adding it to BackStack..
.commit();
In Fragments we dont have back navigation..
We can acheive that through replace() method.
I seen in your code that you are only replace the content frame. and so the result is backpress it comes to activity.
Also be sure that you have your mannual back button in the activity
this is test xml for activity
<?xml version="1.0" encoding="utf-8"?>
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Back" />
<FrameLayout
android:id="#+id/activity_main_content_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
Use
Fragment fragment = new MainMenuLayout();
ft.replace(R.id.activity_main_content_fragment, fragment);
ft.addToBackStack(null);// TODO parameter here it tag of fragment or null or "" String
ft.commit();
For more information about fragments backstack go through this android developer refrence :-Fragment BackStack
Related
I am having trouble going back to previous fragment on backpress from current fragment.
I have Two fragments and i navigate to second fragment on click and when i try to click back from the second fragment, i want to go back to the previous fragment but instead the app exits on backpress. below is the code i am using..
Fragment1 calling second fragment
UserFragment frag = new UserFragment()
FragmentTransaction transaction = getFragmentManager().beginTransaction();
frag.setArguments(bundle);
transaction.addToBackStack("UserActivity");
transaction.replace(android.R.id.content, frag, "UserActivity").addToBackStack(null);
transaction.commit();
In second Fragment i have implemented an interface OnBackpress and over riding the below method
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() != 0) {
if(getFragmentManager().findFragmentByTag("UserActivity") != null){
Log.e("UserActivity",getFragmentManager().findFragmentByTag("UserActivity").toString());
getFragmentManager().popBackStack();
};
}
}
But on back press the app exits. Instead i want to go back to previous fragment. What mistake am i doing? please help. thanks
You need to add you first fragment to back stack properly, you are doing it wrong in your first part of the code.
Use the following code instead.
UserFragment frag = new UserFragment()
FragmentTransaction transaction = getFragmentManager().beginTransaction();
frag.setArguments(bundle);
transaction.addToBackStack("UserActivity");
transaction.replace(android.R.id.content, frag, "UserActivity");
transaction.commit();
Also there is no need to add any code in your onBackPressed after above change.
First, you need to add your fragments to the backstack:
public static void addFragment(FragmentManager fragmentManager, Fragment fragment, int id){
fragmentManager.beginTransaction().add(id, fragment).addToBackStack(null).commit();
}
Then you need to override the onBackPressed, which is a method gets called whenever a user clicks the back button:
#Override
public void onBackPressed() {
super.onBackPressed();
if(getSupportFragmentManager().getBackStackEntryCount() == 0){
button.setVisibility(View.VISIBLE);
}
}
please change to add() instead of replace() in your code..
UserFragment frag = new UserFragment()
FragmentTransaction transaction = getFragmentManager().beginTransaction();
frag.setArguments(bundle);
transaction.addToBackStack("UserActivity");
transaction.add(android.R.id.content, frag, "UserActivity").addToBackStack(null);
transaction.commit();
This will solve your problem.
i have app like this
one activity and inside it >
fragment a (loaded when run app also from menu can open it )
fragment b (open it from just menu)
fragment c (can open it from fragment a and also can open it from menu)
also inside fragment c there are 4 child fragments
in main activity(using navigation drawer as source) i call fragment a in oncreate like this
FragmentManager fragmentManager=getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.fragment_place,new First_Fragment()).addToBackStack("First").commit();
my problem is how to control back button to always back to fragment a and when fragment a is open close app
i was using addToBackStack(null) but is not what i want because will show all history of fragments that i opened
When adding fragment a to the back stack "addToBackStack(String name)" pass in a name.
Then listen for on back presses in your fragments
FragmentManager fm = getFragmentManager();
fm.addOnBackStackChangedListener(new OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
}
});
make sure to stop listening when each fragment is not being shown.
Then you can pop back to the named fragment added to the back stack
FragmentManager fm = getActivity()
.getSupportFragmentManager();
fm.popBackStack ("name", FragmentManager.POP_BACK_STACK_INCLUSIVE);
Make sure the rest of your fragment transactions are not added to the back stack. This should give you the behavior you want.
addToBackStack(String tag) is used to add the fragment to backstack and it contains the string as parameter. This parameter can be null or have some value.
If you pass null, it will add your fragment to backstack with tag null. addToBackStack(null) doesn't mean that your fragment is not added to backstack.
If you want your fragment will not be added to backstack, then just delete this line.
If you are adding your fragment to backstack and want it to be visible onBackPressed, then you can use
getSupportFragmentManager().popBackStackImmediate(/* Fragment TAG */,0);
CODE:- Try the below code and let me know.
Copy the below function in your main Activity.
/**
* function to show the fragment
*
* #param name fragment to be shown
* #param tag fragment tag
*/
public void showFragment(Fragment name, String tag) {
FragmentManager fragmentManager = getSupportFragmentManager();
// check if the fragment is in back stack
boolean fragmentPopped = fragmentManager.popBackStackImmediate(tag, 0);
if (fragmentPopped) {
// fragment is pop from backStack
} else {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, name, tag);
fragmentTransaction.addToBackStack(tag);
fragmentTransaction.commit();
}}
Show fragment using the below code.
showFragment(yourFragment, yourFragmentTag);
In mainActivity onBackPressed.
#override
public void onBackPressed(){
FragmentTransaction fts = getSupportFragmentManager().beginTransaction();
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() >= 2) {
// always show your fragment a here
showFragment(new FragmentA(), FragmentA.class.getSimpleName());
} else {
// finish your activity
}
}
My activity consists of navigation drawer and currently have 5 options in the left menu. Which all opens in fragment.
I am looking for a way to keep a stack of all the fragments so when the user presses back button he moves to previous fragment.
Like- Activity consists of drawer menu which have 5 options menu1, menu2, menu3, menu4, menu5 having corresponding fragments F1, F2, F3, F4, F5.
User presses menu1 he is forwarded to F1
Then presses menu2, and then menu4.
When the user is at F4 and he presses back he should be moved to F2 rather than exiting the activity or app.
How can it implemented and example or sample code preferred.
I currently use this code but it does not help me out
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment)
.addToBackStack(null)
.commit();
I found some workaround for your query :
Override onBackPressed() in code
Use methods related to backstack maintained which contains your all fragment transactions
public void onBackPressed(){
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
Log.i("MainActivity", "popping backstack");
fm.popBackStack(); // this will display last visible fragment
getActinBar().setTitle(mTitle); // save your title in some variable and restore here
} else {
Log.i("MainActivity", "nothing on backstack, calling super");
super.onBackPressed(); // system will handle back key itself
}
}
Reference answer : this
I used to replace Fragment like as below :
public void replaceFragment(Fragment fragment, boolean addToBackStack, int transition) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.activity_main_relative_container, fragment, fragment.getClass().getName());
ft.setTransition(transition);
if (addToBackStack) {
ft.addToBackStack(fragment.getClass().getName());
}
ft.commitAllowingStateLoss();
}
// While to replace Fragment
replaceFragment(mFragment, true, FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
// False for not adding Fragment in back stack and true to add.
Hope this helps.
You need to add fragment to backstack
private FragmentTransaction m_fragmentTransaction;
FragmentOne m_fragOne = new FragmentOne();
m_fragmentTransaction = m_fragmentManager.beginTransaction();
m_fragmentTransaction.replace(R.id.dl_flContainer, m_fragOne , FragmentOne.class.getSimpleName());
m_fragmentTransaction.addToBackStack(FragmentOne.class.getSimpleName());
m_fragmentTransaction.commit();
I have created 3 Fragments namely (FragmentA, FragmentB, FragmentC) and one MainActivity.
There is a button in each fragment which replaces itself with next Fragment till FragmentC.
I am replacing FragmentA (with) FragmentB (then with) FragmentC.
Transaction from FragmentA to FragmentB uses below function
#Override
public void fragmentreplacewithbackstack(Fragment fragment, String tag) {
FragmentManager fragmentManager=getSupportFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.contner,fragment , tag);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
// fragmentManager.executePendingTransactions();
}
Transaction from FragmentB to FragmentC uses below function
public void fragmentreplace(Fragment fragment,String tag){
FragmentManager fragmentManager=getSupportFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.contner,fragment , tag);
fragmentTransaction.commit();
}
problem is when i press back button from FragmentC, FragmentC and FragmentA overlap with each other.
You need to add Fragment C to backstack as well if you wanna go to Fragment B on back press from here.
So call the below for Fragment C as well.
fragmentTransaction.addToBackStack(null);
EDIT - Change this current method you are using to go from B to C,
public void fragmentreplace(Fragment fragment,String tag){
FragmentManager fragmentManager=getSupportFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.contner,fragment , tag);
fragmentTransaction.addToBackStack(null); //this will add it to back stack
fragmentTransaction.commit();
}
I had the same problem and this answer of Budius helped me a lot.
You can solve your issue in the following way:
1) Instantiate the following listener (you have to keep reference of the FragmentC's instance) and, since fragmentA is the only fragment added to the backstack, when the user presses the back button, the number of transactions in the backstack will be zero
private OnBackStackChangedListener backStackChangedListener = new OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if(getSupportFragmentManager().getBackStackEntryCount()==0) {
if(fragmentC!=null) {
getSupportFragmentManager().beginTransaction().remove(fragmentC).commit();
}
}
}
};
2) Add the listener in the MainActivity when the latter is started
getSupportFragmentManager().addOnBackStackChangedListener(backStackChangedListener);
3) Remove the listener when the activity is stopped
why don't you just make a fragment activity with a frame layout in which you can replace that frame with any fragment..
Screen extends FragmentActivity
{
protected void onCreate(Bundle b)
{
super.onCreate(b);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.work);
callPerticularScreen(screenNumber,false,null,null);
}
public void callPerticularScreen(int screenNumber,boolean addToBackStack,String nameTag,Bundle b)
{
switch(screenNumber)
{
case registrationScreen:
callFragForMiddleScreen(registrationPageFrag,addToBackStack,nameTag);
break;
case dashboardScreen:
callFragForMiddleScreen(dashboardFrag,addToBackStack,nameTag);
break;
default:
break;
}
}
}
now from any fragment screen you can call this function to replace your fragment with another..like..
private void callFragForMiddleScreen(Fragment frag,boolean addToBackStack,String nameTag)
{
transFragMiddleScreen=getFragManager().beginTransaction();
transFragMiddleScreen.replace(getMiddleFragId(),frag);
if(addToBackStack)
{
transFragMiddleScreen.addToBackStack(nameTag);
}
transFragMiddleScreen.commit();
//getFragManager().executePendingTransactions();
}
from your fragement just call
Frag1 extends Fragment
{
onActivityCreate()
{
middleScreen=(Screen) getActivity();
middleScreen.callPerticularScreen(1,true,"tag");
}
}
layout for fragment activity..
<RelativeLayout
android:id="#+id/rl2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/rl" >
<FrameLayout
android:id="#+id/middle_screen"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
</RelativeLayout>
just don't add the fragment B to back stack so that you can come from c-> a directly.
25 support library
for example if you have
A -> B -> C
A id is 0
B id is 1
C id is 2
to rollback to A fragment just call
getFragmentManager().popBackStackImmediate(0 /* ID */, 0 /* flag */);
0 - is ID of backstack entry to rollback
or
popBackStackImmediate(1, FragmentManager.POP_BACK_STACK_INCLUSIVE)
FragmentManager.POP_BACK_STACK_INCLUSIVE, it means you want also remove supplied ID
also you can call
getFragmentManager().popBackStackImmediate("stack_name", 0)
"stack_name" it's a name of backstack to revert
for example
A -> B -> C -> D
A in MAIN_BACK_STACK
B in MAIN_BACK_STACK
C in SEPARATE_BACK_STACK
D in SEPARATE_BACK_STACK
if you want to revert to fragment B
just call
getFragmentManager().popBackStackImmediate("MAIN_BACK_STACK", 0)
or
getFragmentManager().popBackStackImmediate("SEPARATE_BACK_STACK", FragmentManager.POP_BACK_STACK_INCLUSIVE)
I have an Activity and many fragments inflated in same FrameLayout
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
example: mainActivity > any fragment (press back button) > activity is blank.
In onCreate:
layout = (FrameLayout)findViewById(R.id.content_frame);
layout.setVisibility(View.GONE);
When I start a fragment:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, profileFragment);
ft.addToBackStack(null);
ft.commit();
layout.setVisibility(View.VISIBLE);
I suppose I need to make the frameLayout's visibility GONE again on back pressed, but how do I do this?
I tried onBackPressed and set layout.setVisibility(View.GONE); but I cannot go back through fragments, as I go directly to main page.
If you have more than one fragment been used in the activity or even if you have only one fragment then the first fragment should not have addToBackStack defined. Since this allows back navigation and prior to this fragment the empty activity layout will be displayed.
// fragmentTransaction.addToBackStack() // dont include this for your first fragment.
But for the other fragment you need to have this defined otherwise the back will not navigate to earlier screen (fragment) instead the application might shutdown.
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
else {
int fragments = getSupportFragmentManager().getBackStackEntryCount();
if (fragments == 1) {
finish();
} else if (getFragmentManager().getBackStackEntryCount() > 1) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
}
To add a fragment
getSupportFragmentManager().beginTransaction()
.replace(R.id.layout_main, dashboardFragment, getString(R.string.title_dashboard))
.addToBackStack(getString(R.string.title_dashboard))
.commit();
Sorry for the late response.
You don't have to add ft.addToBackStack(null); while adding first fragment.
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, profileFragment);
// ft.addToBackStack(null); --remove this line.
ft.commit();
// ... rest of code
If you want to track by the fragments you should override the onBackPressed method, like this
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() == 1) {
finish();
} else {
super.onBackPressed();
}
}
You can override onBackPressed and check to see if there is anything on the backstack.
#Override
public void onBackPressed() {
int fragments = getFragmentManager().getBackStackEntryCount();
if (fragments == 1) {
// make layout invisible since last fragment will be removed
}
super.onBackPressed();
}
Just don't add the first fragment to back stack
Here is the Kotlin code that worked for me.
val ft = supportFragmentManager.beginTransaction().replace(container, frag)
if (!supportFragmentManager.fragments.isEmpty()) ft.addToBackStack(null)
ft.commit()
On a recent personal project, I solved this by not calling addToBackStack if the stack is empty.
// don't add the first fragment to the backstack
// otherwise, pressing back on that fragment will result in a blank screen
if (fragmentManager.getFragments() != null) {
transaction.addToBackStack(tag);
}
Here's my full implementation:
String tag = String.valueOf(mCurrentSectionId);
FragmentManager fragmentManager = mActivity.getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(tag);
if (fragment != null) {
// if the fragment exists then no need to create it, just pop back to it so
// that repeatedly toggling between fragments doesn't create a giant stack
fragmentManager.popBackStackImmediate(tag, 0);
} else {
// at this point, popping back to that fragment didn't happen
// So create a new one and then show it
fragment = createFragmentForSection(mCurrentSectionId);
FragmentTransaction transaction = fragmentManager.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.replace(R.id.main_content, fragment, tag);
// don't add the first fragment to the backstack
// otherwise, pressing back on that fragment will result in a blank screen
if (fragmentManager.getFragments() != null) {
transaction.addToBackStack(tag);
}
transaction.commit();
}
irscomp's solution works if you want to end activity when back button is pressed on first fragment. But if you want to track all fragments, and go back from one to another in back order, you add all fragments to stack with:
ft.addToBackStack(null);
and then, add this to the end of onCreate() to avoid blank screen in last back pressed; you can use getSupportFragmentManager() or getFragmentManager() depending on your API:
FragmentManager fm = getSupportFragmentManager();
fm.addOnBackStackChangedListener(new OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if(getSupportFragmentManager().getBackStackEntryCount() == 0) finish();
}
});
Final words: I don't suggest you to use this solution, because if you go from fragment1 to fragment 2 and vice versa 10 times, when you press back button 10 times it will do it in back order which users will not want it.
Almost same as Goodlife's answer, but in Xamarin.Android way:
Load fragment (I wrote helper method for that, but it's not necessary):
public void LoadFragment(Activity activity, Fragment fragment, string fragmentTitle = "")
{
var fragmentManager = activity.FragmentManager;
var fragmentTransaction = fragmentManager.BeginTransaction();
fragmentTransaction.Replace(Resource.Id.mainContainer, fragment);
fragmentTransaction.AddToBackStack(fragmentTitle);
fragmentTransaction.Commit();
}
Back button (in MainActivity):
public override void OnBackPressed()
{
if (isNavDrawerOpen()) drawerLayout.CloseDrawers();
else
{
var backStackEntryCount = FragmentManager.BackStackEntryCount;
if (backStackEntryCount == 1) Finish();
else if (backStackEntryCount > 1) FragmentManager.PopBackStack();
else base.OnBackPressed();
}
}
And isNavDrawerOpen method:
bool isNavDrawerOpen()
{
return drawerLayout != null && drawerLayout.IsDrawerOpen(Android.Support.V4.View.GravityCompat.Start);
}
I still could not fix the issue through getBackStackEntryCount() and I solved my issue by making the main page a fragment too, so in the end I have an activity with a FrameLayout only; and all other fragments including the main page I inflate into that layout. This solved my issue.
I had the same problem when dealing with Firebase's Ui Login screen. When back button was pressed it left a blank screen.
To solve the problem I just called finish() in my onStop() method for said Activity. Worked like a charm.
If you have scenario like me where a list fragment opens another details fragment, and on back press you first need to show the list fragment and then get out the whole activity then, addToBackStack for all the fragment transactions.
and then on the activity, do like this (courtesy: #JRomero's answer, #MSaudi's comment)
#Override
public void onBackPressed() {
int fragments = getFragmentManager().getBackStackEntryCount();
if (fragments == 1) {
// make layout invisible since last fragment will be removed
}
super.onBackPressed();
}
Just Comment or Remove transaction.addToBackStack(null) in your code.Below is code to change fragment in kotlin.
fun ChangeFragment(activity: MainActivity, fragment: Fragment) {
val transaction: FragmentTransaction =
activity.getSupportFragmentManager().beginTransaction()
transaction.replace(R.id.tabLayoutContainer, fragment)
transaction.commit()
}