I found a ton of these messages in StackOverflow. Like those many other people, I have the same problem with tab contents overlapping when switching tabs. None of the advise
What's wrong?
After a quick look through the code for the ActionBarActivity
, there seems to be a bug for the ICS
and above part of the implementation of the ActionBar
(the code should work for pre ICS
devices) which also takes care of the tabs.
In the ActionBarImplICS
class which represents the implementation for ICS
devices it seems the FragmentTransaction
passed to the onTabUnselected()
callback is completely useless as it isn't committed anywhere after the listener's callback returns(the transaction is committed for the other two callbacks of the TabListener
). So a committed fragment will never be detached from the layout on a tab selection and it will stay getting the overlapping content(due to the FrameLayout
which holds both fragments).
I've written another implementation of the TabListener
interface which does all of its job from only one of the callbacks which isn't affected by the above bug(onTabSelected()
):
public class TabListenerImpl implements ActionBar.TabListener {
private List<TabInfo> mTabs = new ArrayList<TabInfo>();
private Context mContext;
public TabListenerImpl(Context context) {
mContext = context;
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// iterate over all of the tabs, match the tag we have and see if
// we also have a fragment instance for it. If we don't, create one
// and add it to the container, if we have an instance simply attach
// it. Detach every other tag which doesn't match the tag.
for (TabInfo t : mTabs) {
if (tab.getTag() == t.tag) {
if (t.pageFragment == null) {
t.pageFragment = Fragment.instantiate(mContext,
t.clazz.getName());
ft.add(android.R.id.content, t.pageFragment, t.tag);
} else {
ft.attach(t.pageFragment);
}
} else {
if (t.pageFragment != null && !t.pageFragment.isDetached()) {
ft.detach(t.pageFragment);
}
}
}
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// faulty method
}
/**
* Call this method BEFORE you call the actionBar.addTab() method!
*
* @param tag
* a String representing the tag that was set on the tab to
* identify itself
* @param clazz
* the class of the Fragment
*/
public void addTab(String tag, Class<? extends Fragment> clazz) {
TabInfo ti = new TabInfo();
ti.clazz = clazz;
ti.tag = tag;
mTabs.add(ti);
}
// wrapper class
private class TabInfo {
Class<? extends Fragment> clazz;
Fragment pageFragment;
String tag;
}
}
Which you could then use as:
TabListenerImpl listener = new TabListenerImpl(this);
Tab tab = actionBar.newTab().setText("TAB1").setTag("TAB1").setTabListener(listener);
listener.addTab("TAB1", Tab1Class.class);
actionBar.addTab(tab);
tab = actionBar.newTab().setText("TAB2").setTag("TAB2").setTabListener(listener);
listener.addTab("TAB2", Tab2Class.class);
actionBar.addTab(tab);
I would advise you to set a container as the content view(and also for the tab content) and not use the android.R.id.content
container. Keep in mind that my implementation doesn't take care of configuration changes.