简体   繁体   中英

Bring Fragment to Front (No fragment recreation)

I have three fragments F1 F2 F3 F4 all are accessible from sidebar.

all four can be called at any time and in any order,

Now I want if, F1 is already clicked(created) then never again create F1, but only bring back fragment F1 to front using fragment manager. Same for all other fragment

So far i tried this for every fragment in my container (FRAGMENT ACTIVITY)

if (fragmentManager.findFragmentByTag("apps")==null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);

Fragment newFragment = new CategoriesFragment();
transaction.replace(R.id.content_frame, newFragment, "apps");
transaction.addToBackStack("apps");
transaction.commit();   
} else{

}

If part ensures me NO fragment is recreated (If its created already) again, but what should i write in else part so that already created fragment can be brought to front in View Hierarchy

Please Help, i'm stuck at this for 2 days.

I would put this code in activity class, that must have FrameLayout with id R.id.fragment_container .

private Fragment1 F1;
private Fragment2 F2;
private Fragment3 F3;
private Fragment4 F4;       

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    F1 = new Fragment1();
    getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, F1).commit();
    F2 = new Fragment2();
    getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, F2).commit();
    F3 = new Fragment3();
    getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, F3).commit();
    F4 = new Fragment4();
    getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, F4).commit();

    //if needed show F1
    getSupportFragmentManager().beginTransaction().show(F1).commit();

}

And add this for button click:

public void onBtnClick(View view){
    if(mShowF1){
        getSupportFragmentManager().beginTransaction().show(F1).commit();
        getSupportFragmentManager().beginTransaction().hide(F2).commit();
        getSupportFragmentManager().beginTransaction().hide(F3).commit();
        getSupportFragmentManager().beginTransaction().hide(F4).commit();
    }
    //...
}

On button click(s) you can show, that fragment that you want and hide others.

NOTE (@developer1011): For use after activity save state call commitAllowingStateLoss () . Use with care, because fragment is not restored with activity restoration.

NOTE: MainActivity should implement OnFragmentInteractionListener for each Fragment.

public class MainActivity extends FragmentActivity implements Fragment1.OnFragmentInteractionListener, Fragment2.OnFragmentInteractionListener, Fragment3.OnFragmentInteractionListener, Fragment4.OnFragmentInteractionListener {//..

    @Override
    public void onFragmentInteraction(Uri uri) {
        //
    }
}

Get the fragment by tag and replace it in the container,

else{
Fragment existingFragment = (CategoriesFragment)fragmentManager.findFragmentByTag("apps");
transaction.replace(R.id.content_frame,existingFragment, "apps");
transaction.addToBackStack("apps");
transaction.commit();
}

UPDATE: you can use hide and show fragment to avoid recreation.instead of using "transaction.replace()"

fragmentTransaction.hide(<oldFragment>);
fragmentTransaction.show(<newFragment>);

JAVA:

If you are just trying to add a Fragment without having to worry about recreating it then I think this method I have wrote to add Fragment will do you job.

public static void attachFragment ( int fragmentHolderLayoutId, Fragment fragment, Context context, String tag ) {


    FragmentManager manager = ( (AppCompatActivity) context ).getSupportFragmentManager ();
    manager.findFragmentByTag ( tag );
    FragmentTransaction ft = manager.beginTransaction ();

    if (manager.findFragmentByTag ( tag ) == null) { // No fragment in backStack with same tag..
        ft.add ( fragmentHolderLayoutId, fragment, tag );
        ft.addToBackStack ( tag );
        ft.commit ();
    }
    else {
        for (Fragment frag : manager.getFragments()){
          ft.hide(frag)
        }
        ft.show ( manager.findFragmentByTag ( tag ) ).commit ();
    }
}

Kotlin:

fun attachFragment(fragmentHolderLayoutId: Int, fragment: Fragment?, tag: String?) {
    val manager: FragmentManager = supportFragmentManager
    val ft: FragmentTransaction = manager.beginTransaction()
    if (manager.findFragmentByTag(tag) == null) { // No fragment in backStack with same tag..
        ft.add(fragmentHolderLayoutId, fragment!!, tag)
        ft.addToBackStack(tag)
        ft.commit()
    } else {
        //Hide other fragments
        for (frag in manager.fragments){
            ft.hide(frag)
        }
        //Shows the selected fragment.
        ft.show(manager.findFragmentByTag(tag)!!).commit()
    }
}
  1. Use a simple ArrayList<Fragment> for your Fragments, and add them in order, so that you know get(0) will get F1, get(1) gets F2, etc.

  2. Create the Fragments as singletons. In each fragment add a static field and method:

     private static Fragment mMyInstance = null; public static Fragment newInstance() { if (mMyInstance == null) { mMyInstance = new F1(); } return mMyInstance; }
  3. Create the Fragments with the static method and add them to the ArrayList.

  4. In each Fragment add the setRetainInstance(true); command to the onCreate() method.

Now when you add the Fragment with the FragmentManager, onCreate() will only be called the first time, but onCreateView() will be called every time. You want to inflate the view and wire the widgets each time, just en case your Activity got recreated because of a configuration change. But you can check something you add to see if it's the first time or not, and reset the widgets to their previous state if not. So, you will need member variables in your Fragments to keep track of their state. Override onStop() to save state, and reapply it in onCreateView() after wiring up the widgets.

Then when the sidebar button is pressed, you get the Fragment that corresponds to that button, remove the previous Fragment, and add the current one with the FragmentManager (or just use the replace() command instead of remov()/add()).

If you are using the Support Fragment, then this static method does the job.

    /**
 * Takes a Fragment TAG and tries to find the fragment in the manager if it exists and bring it to front.
 * if not, will return false;
 * @param manager
 * @param tag
 */
public static boolean resurfaceFragment(FragmentManager manager, String tag ){
    Fragment fragment = manager.findFragmentByTag(tag);
    FragmentTransaction transaction = manager.beginTransaction();
    if (fragment!=null){
        for (int i = 0; i < manager.getFragments().size(); i++) {
            Fragment f =  manager.getFragments().get(i);
            transaction.hide(f);

        }
        transaction.show(fragment).commit();
        return true;
    }

    return false;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM