Android; Фрагменты перекрываются при переключении вкладок

Прежде всего, спасибо всем вам за это великое сообщество.

Я пытаюсь выполнить пример кода демонстрации поддержки для реализации интерфейса с вкладками-фрагментами.

На верхнем уровне я пытаюсь реализовать две вкладки, связывать один фрагмент с каждой вкладкой и отображать фрагменты, когда каждая вкладка выбрана соответствующим образом.

В настоящее время у меня есть два вопроса (но я уверен, что они связаны …)

1) фрагменты для каждой вкладки перекрывают друг друга. Это может быть связано с неправильным присоединением / отсоединением фрагмента.

2) Третий фрагмент тайны создается где-то и перекрывает другие фрагменты


На эмуляторе (и на физическом устройстве) вы можете увидеть, что накладываются два фрагмента при выборе одной вкладки

Когда выбрано tab1, фрагмент 1 и неизвестный фрагмент перекрываются.

Когда tab2 выбран, фрагмент 1 и фрагмент 2 перекрываются.


Ссылки на скриншоты (недостаточно репутации для загрузки фотографий …)

(Перекрытие tab1) http://s8.postimg.org/kv81yz745/tab1_overlapping.png

(Tab2 overlapping) http://s8.postimg.org/3tf7wvs91/tab2_overlapping.png


Здесь я разделил текст в каждом фрагменте для целей демонстрации / ясности.

Ссылки на эти скриншоты приведены ниже в моем комментарии / ответе. (Недостаточно репутации для загрузки более двух ссылок …)

Макет действий (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> 

Исходный код

 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's 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's 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(); } } } 

Solutions Collecting From Web of "Android; Фрагменты перекрываются при переключении вкладок"

После нескольких дней экспериментов я получил это, чтобы работать правильно.

В методе onCreate моего класса TabbedInfoHome при создании новых экземпляров фрагментов в первый раз ( savedInstanceState == null ) я принудительно this.getSupportFragmentManager().executePendingTransactions() ожидающие транзакции в FragmentTransaction с помощью this.getSupportFragmentManager().executePendingTransactions()

Это объяснение немного отличается от документации, найденной по адресу: http://developer.android.com/reference/android/app/FragmentManager.html#executePendingTransactions ()

После того, как FragmentTransaction выполняется с помощью FragmentTransaction.commit() , его планируется выполнить асинхронно > в основном потоке процесса. Если вы хотите немедленно выполнить любые такие ожидающие операции операции, вы можете вызвать эту функцию.

Один из нерешенных вопросов, который у меня остается, заключается в том, как отсутствие немедленного выполнения незавершенных транзакций проявляется в поведении, рассматриваемом в исходном вопросе.

Другими словами … как делает this.getSupportFragmentManager().executePendingTransactions() объясняет перекрывающиеся фрагменты?


Отредактированный код приведен ниже; Добавление одной строки

 @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); } 

Я также получаю эту проблему на Nexus 5.

Я думаю, что у нас есть другое решение лучше, чем удалять решение, используя этот способ.

Во all your xml files необходимо определить цвет фона для него, это решит проблему:

Добавьте этот android:background="@android:color/black" в тег View, который вы определили.

Я пытаюсь сделать то же самое, и сегодня утром были те же проблемы. Я разрешаю их с информацией, полученной мной из другого вопроса.

В моем случае я не использую SherlockActionBar, но решение должно работать на вас.

В той части, где вы проверяете, есть ли фрагмент, завышенный для вкладки, я использую:

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

Я полагаю, это должно сработать для вас, если вы соответствуете его командам SherlockActionBar (потому что я читал информацию, которую они использовали с SherlockActionBar).

Надеюсь, это сработает для вас!

Дано много решений, но я не смог решить проблему из-за глупой ошибки. Проблема заключалась в том, что в новом SDK по умолчанию активность расширена до «ActionbarActivity», в которой создается фрагмент, но они перекрываются. Чтобы решить эту проблему, расширяет вашу деятельность до «FragmentActivity»