Android fragments overlap when switching tabs

First of all, thank you all for this great community.

I am trying to run sample support demo code to implement fragment tabbed interface.

At the top, I am trying to implement two tabs, associate one fragment with each tab and display fragments when each tab is selected accordingly.

I currently have two problems (but I'm sure they are related ...)

1) Fragments for each tab overlap with each other. This may be due to improper attachment / detachment of the fragment.

2) The third fragment of the mystery is created somewhere and overlaps other fragments, and


On the emulator (and on the physical device), you can see that two fragments overlap when you select one tab

When tab1 is selected, fragment 1 and the unknown fragment overlap.

When tab2 is selected, fragment 1 and fragment 2 overlap.


Links to screenshots (not enough reputation to upload photos ...)

(tab 1 overlaps) http://s8.postimg.org/kv81yz745/tab1_overlapping.png

(tab2 overlaps) http://s8.postimg.org/3tf7wvs91/tab2_overlapping.png


here, I divided the text in each fragment for demonstration / clarity purposes.

Links to these screenshots are given below in my comment / answer. (not enough reputation to download more than two links ...)

Action Layout (fragment_tabs.xml)

<TabHost xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/tabhost" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TabWidget android:id="@android:id/tabs" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0"/> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="0dp" android:layout_height="0dp" android:layout_weight="0"/> <FrameLayout android:id="@+id/realtabcontent" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> </LinearLayout> </TabHost> 

Source

 public class TabbedInfoHome extends SherlockFragmentActivity { TabHost mTabHost; TabManager mTabManager; static String tag1name = "simple1"; static String tag2name = "simple2"; static String tab1string = "You are looking at fragment 1"; static String tab2string = "You are looking at fragment 2"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_tabs); if (savedInstanceState == null) { // Do first time initialization -- add initial fragment. Fragment frag1 = CountingFragment.newInstance(tab1string); Fragment frag2 = CountingFragment.newInstance(tab2string); FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.add(R.id.realtabcontent, frag1, tag1name); ft.add(R.id.realtabcontent, frag2, tag2name); ft.commit(); } else { mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); } mTabHost = (TabHost)findViewById(android.R.id.tabhost); mTabHost.setup(); mTabManager = new TabManager(this, mTabHost, R.id.realtabcontent); mTabManager.addTab(mTabHost.newTabSpec(tag1name) .setIndicator(tag1name), TabbedInfoHome.CountingFragment.class, null); mTabManager.addTab(mTabHost.newTabSpec(tag2name) .setIndicator(tag2name), TabbedInfoHome.CountingFragment.class, null); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString("tab", mTabHost.getCurrentTabTag()); } public static class CountingFragment extends SherlockFragment { String displayString; String FRAGMENT_TAG = this.getClass().getSimpleName(); /** * Create a new instance of CountingFragment, providing "num" * as an argument. */ static CountingFragment newInstance(String toDisplay) { CountingFragment f = new CountingFragment(); Bundle args = new Bundle(); args.putString("string", toDisplay); f.setArguments(args); return f; } /* When creating, retrieve this instance number from its arguments. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); displayString = getArguments() != null ? getArguments().getString("string") : "no string was passed in!"; } /* The Fragment UI is just a simple text view showing its * instance number. */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.hello_world, container, false); View tv = v.findViewById(R.id.text); boolean separateStrings = false; /* the overlapping is hard to decipher, so * lets illustrate how both fragments are appearing */ if(separateStrings) { String temp; /* b/c I only created TWO instances of the CountingFragments object, * there should only be TWO "displayStrings" to consider... */ if( (displayString.compareTo(tab1string) == 0) ) { /* user clicked tab 1 */ temp = "\n\n\n\n" + displayString; } else if( (displayString.compareTo(tab2string) == 0) ) { /* user clicked tab2 */ temp = "\n\n\n\n\n\n\n" + displayString; } else { /* unknown CountingFragment instance */ temp = "What am I doing here..??? "; } ((TextView)tv).setText(temp); } else { /* normal case of the fragment being shown; (but they overlap!) */ ((TextView)tv).setText(displayString); } return v; } } /** * This is a helper class that implements a generic mechanism for * associating fragments with the tabs in a tab host. It relies on a * trick. Normally a tab host has a simple API for supplying a View or * Intent that each tab will show. This is not sufficient for switching * between fragments. So instead we make the content part of the tab host * 0dp high (it is not shown) and the TabManager supplies its own dummy * view to show as the tab content. It listens to changes in tabs, and takes * care of switch to the correct fragment shown in a separate content area * whenever the selected tab changes. */ public static class TabManager implements TabHost.OnTabChangeListener { private final FragmentActivity mActivity; private final TabHost mTabHost; private final int mContainerId; private final HashMap<String, TabInfo> mTabs = new HashMap<String, TabInfo>(); TabInfo mLastTab; static final class TabInfo { private final String tag; private final Class<?> clss; private final Bundle args; private Fragment fragment; TabInfo(String _tag, Class<?> _class, Bundle _args) { tag = _tag; clss = _class; args = _args; } } static class DummyTabFactory implements TabHost.TabContentFactory { private final Context mContext; public DummyTabFactory(Context context) { mContext = context; } @Override public View createTabContent(String tag) { View v = new View(mContext); v.setMinimumWidth(0); v.setMinimumHeight(0); return v; } } public TabManager(FragmentActivity activity, TabHost tabHost, int containerId) { mActivity = activity; mTabHost = tabHost; mContainerId = containerId; mTabHost.setOnTabChangedListener(this); } public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) { tabSpec.setContent(new DummyTabFactory(mActivity)); String tag = tabSpec.getTag(); TabInfo info = new TabInfo(tag, clss, args); // Check to see if we already have a fragment for this tab, probably // from a previously saved state. If so, deactivate it, because our // initial state is that a tab isn't shown. info.fragment = mActivity.getSupportFragmentManager().findFragmentByTag(tag); if (info.fragment != null ) { // && !info.fragment.isDetached()) { Log.d("addingTab", "we already have a fragment for this tab. tabInfo.fragment.id: " + info.fragment.getId()); FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction(); ft.detach(info.fragment); ft.commit(); mActivity.getSupportFragmentManager().executePendingTransactions(); } // associate the tabSpec tag with a particular TabInfo object mTabs.put(tag, info); mTabHost.addTab(tabSpec); } @Override public void onTabChanged(String tabId) { TabInfo newTab = mTabs.get(tabId); if (mLastTab != newTab) { FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction(); if (mLastTab != null) { if (mLastTab.fragment != null) { ft.detach(mLastTab.fragment); } } if (newTab != null) { if (newTab.fragment == null) { newTab.fragment = Fragment.instantiate(mActivity, newTab.clss.getName(), newTab.args); ft.add(mContainerId, newTab.fragment, newTab.tag); } else { ft.attach(newTab.fragment); } } mLastTab = newTab; ft.commit(); mActivity.getSupportFragmentManager().executePendingTransactions(); } } } 
+7
source share
4 answers

After several days of experimentation, I got this to work correctly.

In the onCreate method of my onCreate class TabbedInfoHome when creating new instances of fragments for the first time ( savedInstanceState == null ), I forcibly executed pending transactions in FragmentTransaction using this.getSupportFragmentManager().executePendingTransactions()

This explanation is slightly different from the documentation found at: http://developer.android.com/reference/android/app/FragmentManager.html#executePendingTransactions ()

After a FragmentTransaction committed using FragmentTransaction.commit() , it must be executed asynchronously > in the main thread of the process. If you want to immediately perform any such pending operations, you can call this function.

One of the unresolved issues that I still have is how the lack of immediate execution of pending transactions is manifested in the behavior discussed in the original question.

In other words ... how does the LACK from this.getSupportFragmentManager().executePendingTransactions() explain the overlapping fragments?


The edited code is given below; single line addition

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_tabs); if (savedInstanceState == null) { // Do first time initialization -- add initial fragment. Fragment frag1 = CountingFragment.newInstance(tab1string); Fragment frag2 = CountingFragment.newInstance(tab2string); FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.add(R.id.realtabcontent, frag1, tag1name); ft.add(R.id.realtabcontent, frag2, tag2name); ft.commit(); this.getSupportFragmentManager().executePendingTransactions(); // <----- This is the key } else { mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); } mTabHost = (TabHost)findViewById(android.R.id.tabhost); mTabHost.setup(); mTabManager = new TabManager(this, mTabHost, R.id.realtabcontent); mTabManager.addTab(mTabHost.newTabSpec(tag1name) .setIndicator(tag1name), TabbedInfoHome.CountingFragment.class, null); mTabManager.addTab(mTabHost.newTabSpec(tag2name) .setIndicator(tag2name), TabbedInfoHome.CountingFragment.class, null); } 
+11
source

I also get this problem on Nexus 5.

I think we have a different solution better than removing the solution using this method.

In all your xml files , should determine the background color for it, it will solve the problem:

Add this android:background="@android:color/black" to the view tag that you defined.

+1
source

I am trying to do the same, and this morning there were the same problems. I authorize them with the information I received from another question.

In my case, I am not using SherlockActionBar, but the solution should work for you.

In the part where you are checking to see if there is a fragment overpriced for the tab, I use:

  // in order to avoid fragment Fragment prevFragment; FragmentManager fm = mActivity.getFragmentManager(); prevFragment = fm.findFragmentByTag(mTag); if (prevFragment != null) { mFragment = prevFragment; } // \previous Fragment management 

I suppose this should work for you if you match its SherlockActionBar commands (because I read the information they used with SherlockActionBar).

Hope this works for you!

0
source

Many solutions have already been given, but I could not solve the problem due to a stupid error. The problem was that in the new SDK, by default, the action extends to the "ActionbarActivity" in which the fragment is created, but they overlap. To solve this problem, expand your activity to "FragmentActivity"

0
source

All Articles