简体   繁体   中英

Previously detached fragment stays visible behind the current, after tab changed (using support library)

Here is my TabListener:

    public class TabListener<T extends Fragment> implements android.support.v7.app.ActionBar.TabListener {

    private Fragment mFragment;
    private final Activity mActivity;
    private final String mTag;
    private final Class<T> mClass;

    public TabListener(Activity activity, String tag, Class<T> cl) {
        mActivity = activity;
        mTag = tag;
        mClass = cl;
    }

    @Override
    public void onTabReselected(Tab arg0, FragmentTransaction arg1) {
        // TODO Auto-generated method stub          
    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {

        mFragment = ((FragmentActivity) mActivity).getSupportFragmentManager().findFragmentByTag(mTag);   // add this

        if (mFragment == null){ 
            mFragment = android.support.v4.app.Fragment.instantiate(mActivity, mClass.getName()); 
            ft.add(android.R.id.content,mFragment,mTag);
        } else {
            ft.attach(mFragment);
        }             
    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        mFragment = ((FragmentActivity) mActivity).getSupportFragmentManager().findFragmentByTag(mTag);   // add this
        if (mFragment != null) {
            //Toast.makeText(mActivity, "detached", Toast.LENGTH_SHORT).show();
            ft.detach(mFragment);
        }
    }

}

And a part of my Activity:

public class RoadMapActivity extends ActionBarActivity {

ListView generalRoadmapList;
ListView mainRoadmapList;
android.support.v7.app.ActionBar actionBar;

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

    actionBar = getSupportActionBar();        
    actionBar.setDisplayShowTitleEnabled(false);
    actionBar.setDisplayUseLogoEnabled(true);       
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    Tab generalTab = actionBar.newTab()
            .setText("General")
            .setTabListener(new TabListener<GeneralListFragment>(this, "general", GeneralListFragment.class));
    actionBar.addTab(generalTab);

    Tab myTab = actionBar.newTab()
                        .setText("My")
                        .setTabListener(new TabListener<MyListFragment>(this, "my", MyListFragment.class));
    actionBar.addTab(myTab);
}

I tried to change the viewGroup from android.R.id.content to a custom view group from the Activity's layout, the next thing will happens:

I have two tabs, A and B. After starting the activity the active tab is A and the content is fragment A. If switching to B, the tab B gets active, but the content is still fragment A. Than change back to tab A, and the content will be fragment B. Change to tab B, content is fragment A... without showing the other fragment behind, but whit a changed content.

I've tried everithing i found on google and here, without any sucess. Does anybody have an idea?

My final solution based on Chris's answer:

    public class TabListener<T extends Fragment> implements android.support.v7.app.ActionBar.TabListener {

    private Fragment mFragment;
    private String mTag;
    private boolean added = false;

    private TabListener(String tag, Fragment fragment) {
        mTag = tag;
        mFragment = fragment;
    }

    @Override
    public void onTabReselected(Tab arg0, FragmentTransaction arg1) {
        // TODO Auto-generated method stub          
    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {

        if (!added){                
            ft.replace(R.id.list_container,mFragment,mTag);
            added = true;
        } else {
            ft.attach(mFragment);
        } 
    }       

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        ft.detach(mFragment);
    }

}

the instatiate of the fragment (every tab has own listener):

        Tab myTab = actionBar.newTab()
                        .setText("My")
                        .setTabListener(new TabListener<MyListFragment>("my", new MyListFragment()));
    actionBar.addTab(myTab);

I've completed your solution, because that way the fragments doesn't destroys and creates on every tab changes, you'll find it in a same state if you change back to them. Only destroys and recreates when the Activity restarts (ex. after orientation change).

Thanks a lot Chris!

You are instantiating your Fragments completely wrong. Have a look at the revised method.

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {

   Fragment mFragment;
   switch(tab.getPosition(){ 
     case 0:
       /* create fragment in here based on which tab, mFragment = new ExampleFrag */ 
       break;
     case 1:
       /* create fragment in here based on which tab, mFragment = new ExampleFrag */ 
       break;
   }

   ft.replace(android.R.id.content, mFragment);
}

@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
   // Dont need to do anything.
}

Much more simple.

Worth noting that you shouldn't use android.R.id.content with the ActionBarActivity as prior to Android 3.0 The support action bar gets added into android.R.id.content and by replacing your fragment into it, you will remove the ActionBar. (Nasty I know.)

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