diff --git a/samples/ApiDemos/src/com/example/android/apis/app/FragmentNestingTabs.java b/samples/ApiDemos/src/com/example/android/apis/app/FragmentNestingTabs.java index e35761216..4331c2aec 100644 --- a/samples/ApiDemos/src/com/example/android/apis/app/FragmentNestingTabs.java +++ b/samples/ApiDemos/src/com/example/android/apis/app/FragmentNestingTabs.java @@ -20,6 +20,7 @@ import android.app.ActionBar; import android.app.ActionBar.Tab; import android.app.Activity; import android.app.Fragment; +import android.app.FragmentManager; import android.app.FragmentTransaction; import android.os.Bundle; import android.widget.Toast; @@ -31,6 +32,7 @@ import android.widget.Toast; public class FragmentNestingTabs extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { + FragmentManager.enableDebugLogging(true); super.onCreate(savedInstanceState); final ActionBar bar = getActionBar(); diff --git a/samples/ApiDemos/src/com/example/android/apis/app/FragmentTabsFragment.java b/samples/ApiDemos/src/com/example/android/apis/app/FragmentTabsFragment.java index f1d8592e3..1d45e4dbe 100644 --- a/samples/ApiDemos/src/com/example/android/apis/app/FragmentTabsFragment.java +++ b/samples/ApiDemos/src/com/example/android/apis/app/FragmentTabsFragment.java @@ -15,7 +15,7 @@ */ package com.example.android.apis.app; -import java.util.HashMap; +import java.util.ArrayList; import com.example.android.apis.R; @@ -29,28 +29,32 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TabHost; +/** + * Sample fragment that contains tabs of other fragments. + */ public class FragmentTabsFragment extends Fragment { - TabHost mTabHost; TabManager mTabManager; - String mCurrentTabTag; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mTabManager = new TabManager(getActivity(), getChildFragmentManager(), + R.id.realtabcontent); + } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_tabs_fragment, container, false); - mTabHost = (TabHost)v.findViewById(android.R.id.tabhost); - mTabHost.setup(); + TabHost host = mTabManager.handleCreateView(v); - mTabManager = new TabManager(getActivity(), getChildFragmentManager(), - mTabHost, R.id.realtabcontent); - - mTabManager.addTab(mTabHost.newTabSpec("result").setIndicator("Result"), + mTabManager.addTab(host.newTabSpec("result").setIndicator("Result"), FragmentReceiveResult.ReceiveResultFragment.class, null); - mTabManager.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"), + mTabManager.addTab(host.newTabSpec("contacts").setIndicator("Contacts"), LoaderCursor.CursorLoaderListFragment.class, null); - mTabManager.addTab(mTabHost.newTabSpec("apps").setIndicator("Apps"), + mTabManager.addTab(host.newTabSpec("apps").setIndicator("Apps"), LoaderCustom.AppListFragment.class, null); - mTabManager.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"), + mTabManager.addTab(host.newTabSpec("throttle").setIndicator("Throttle"), LoaderThrottle.ThrottledLoaderListFragment.class, null); return v; @@ -59,47 +63,37 @@ public class FragmentTabsFragment extends Fragment { @Override public void onViewStateRestored(Bundle savedInstanceState) { super.onViewStateRestored(savedInstanceState); - if (savedInstanceState != null) { - mCurrentTabTag = savedInstanceState.getString("tab"); - } - mTabHost.setCurrentTabByTag(mCurrentTabTag); + mTabManager.handleViewStateRestored(savedInstanceState); } @Override public void onDestroyView() { super.onDestroyView(); - // Need to remember the selected tab so that we can restore it if - // we later re-create the views. - mCurrentTabTag = mTabHost.getCurrentTabTag(); - mTabHost = null; - mTabManager = null; + mTabManager.handleDestroyView(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - outState.putString("tab", mTabHost != null - ? mTabHost.getCurrentTabTag() : mCurrentTabTag); + mTabManager.handleSaveInstanceState(outState); } /** * 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. + * associating fragments with the tabs in a tab host. DO NOT USE THIS. + * If you want tabs in a fragment, use the support v13 library's + * FragmentTabHost class, which takes care of all of this for you (in + * a simpler way even). */ public static class TabManager implements TabHost.OnTabChangeListener { private final Context mContext; private final FragmentManager mManager; - private final TabHost mTabHost; private final int mContainerId; - private final HashMap mTabs = new HashMap(); - TabInfo mLastTab; + private final ArrayList mTabs = new ArrayList(); + private TabHost mTabHost; + private TabInfo mLastTab; + private boolean mInitialized; + private String mCurrentTabTag; static final class TabInfo { private final String tag; @@ -130,40 +124,109 @@ public class FragmentTabsFragment extends Fragment { } } - public TabManager(Context context, FragmentManager manager, TabHost tabHost, - int containerId) { + public TabManager(Context context, FragmentManager manager, int containerId) { mContext = context; mManager = manager; - mTabHost = tabHost; mContainerId = containerId; + } + + public TabHost handleCreateView(View root) { + if (mTabHost != null) { + throw new IllegalStateException("TabHost already set"); + } + mTabHost = (TabHost)root.findViewById(android.R.id.tabhost); + mTabHost.setup(); mTabHost.setOnTabChangedListener(this); + return mTabHost; } public void addTab(TabHost.TabSpec tabSpec, Class clss, Bundle args) { tabSpec.setContent(new DummyTabFactory(mContext)); String tag = tabSpec.getTag(); - TabInfo info = new TabInfo(tag, clss, args); + mTabs.add(info); + mTabHost.addTab(tabSpec); + } - // 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 = mManager.findFragmentByTag(tag); - if (info.fragment != null && !info.fragment.isDetached()) { - FragmentTransaction ft = mManager.beginTransaction(); - ft.detach(info.fragment); - ft.commit(); + public void handleViewStateRestored(Bundle savedInstanceState) { + if (savedInstanceState != null) { + mCurrentTabTag = savedInstanceState.getString("tab"); + } + mTabHost.setCurrentTabByTag(mCurrentTabTag); + + String currentTab = mTabHost.getCurrentTabTag(); + + // Go through all tabs and make sure their fragments match + // the correct state. + FragmentTransaction ft = null; + for (int i=0; i - - - - - - - - - - - - - - diff --git a/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentTabsFragment.java b/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentTabsFragment.java index fbc464dda..441585135 100644 --- a/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentTabsFragment.java +++ b/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentTabsFragment.java @@ -15,173 +15,38 @@ */ package com.example.android.supportv13.app; -import java.util.HashMap; - import com.example.android.supportv13.R; import android.app.Fragment; -import android.app.FragmentManager; -import android.app.FragmentTransaction; -import android.content.Context; import android.os.Bundle; +import android.support.v13.app.FragmentTabHost; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TabHost; public class FragmentTabsFragment extends Fragment { - TabHost mTabHost; - TabManager mTabManager; - String mCurrentTabTag; + private FragmentTabHost mTabHost; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_tabs_fragment, container, false); - mTabHost = (TabHost)v.findViewById(android.R.id.tabhost); - mTabHost.setup(); + mTabHost = new FragmentTabHost(getActivity()); + mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.pager); - mTabManager = new TabManager(getActivity(), getChildFragmentManager(), - mTabHost, R.id.realtabcontent); - - mTabManager.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"), + mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"), CountingFragment.class, null); - mTabManager.addTab(mTabHost.newTabSpec("array").setIndicator("Array"), + mTabHost.addTab(mTabHost.newTabSpec("array").setIndicator("Array"), FragmentPagerSupport.ArrayListFragment.class, null); - mTabManager.addTab(mTabHost.newTabSpec("cursor").setIndicator("Cursor"), + mTabHost.addTab(mTabHost.newTabSpec("cursor").setIndicator("Cursor"), CursorFragment.class, null); - return v; - } - - @Override - public void onViewStateRestored(Bundle savedInstanceState) { - super.onViewStateRestored(savedInstanceState); - if (savedInstanceState != null) { - mCurrentTabTag = savedInstanceState.getString("tab"); - } - mTabHost.setCurrentTabByTag(mCurrentTabTag); + return mTabHost; } @Override public void onDestroyView() { super.onDestroyView(); - // Need to remember the selected tab so that we can restore it if - // we later re-create the views. - mCurrentTabTag = mTabHost.getCurrentTabTag(); mTabHost = null; - mTabManager = null; - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString("tab", mTabHost != null - ? mTabHost.getCurrentTabTag() : mCurrentTabTag); - } - - /** - * 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 Context mContext; - private final FragmentManager mManager; - private final TabHost mTabHost; - private final int mContainerId; - private final HashMap mTabs = new HashMap(); - 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(Context context, FragmentManager manager, TabHost tabHost, - int containerId) { - mContext = context; - mManager = manager; - mTabHost = tabHost; - mContainerId = containerId; - mTabHost.setOnTabChangedListener(this); - } - - public void addTab(TabHost.TabSpec tabSpec, Class clss, Bundle args) { - tabSpec.setContent(new DummyTabFactory(mContext)); - 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 = mManager.findFragmentByTag(tag); - if (info.fragment != null && !info.fragment.isDetached()) { - FragmentTransaction ft = mManager.beginTransaction(); - ft.detach(info.fragment); - ft.commit(); - } - - mTabs.put(tag, info); - mTabHost.addTab(tabSpec); - } - - @Override - public void onTabChanged(String tabId) { - TabInfo newTab = mTabs.get(tabId); - if (mLastTab != newTab) { - FragmentTransaction ft = mManager.beginTransaction(); - if (mLastTab != null) { - if (mLastTab.fragment != null) { - ft.detach(mLastTab.fragment); - } - } - if (newTab != null) { - if (newTab.fragment == null) { - newTab.fragment = Fragment.instantiate(mContext, - newTab.clss.getName(), newTab.args); - ft.add(mContainerId, newTab.fragment, newTab.tag); - } else { - ft.attach(newTab.fragment); - } - } - - mLastTab = newTab; - ft.commit(); - mManager.executePendingTransactions(); - } - } } } //END_INCLUDE(complete) diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentNestingTabsSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentNestingTabsSupport.java index d4005cc8c..dfdbc21c2 100644 --- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentNestingTabsSupport.java +++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentNestingTabsSupport.java @@ -23,7 +23,7 @@ import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTabHost; public class FragmentNestingTabsSupport extends FragmentActivity { - FragmentTabHost mTabHost; + private FragmentTabHost mTabHost; @Override protected void onCreate(Bundle savedInstanceState) { @@ -41,16 +41,6 @@ public class FragmentNestingTabsSupport extends FragmentActivity { FragmentStackFragmentSupport.class, null); mTabHost.addTab(mTabHost.newTabSpec("tabs").setIndicator("Tabs"), FragmentTabsFragmentSupport.class, null); - - if (savedInstanceState != null) { - mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); - } - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString("tab", mTabHost.getCurrentTabTag()); } } //END_INCLUDE(complete) diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabs.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabs.java index 9c9e5f414..7a7e2fcaf 100644 --- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabs.java +++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabs.java @@ -27,7 +27,7 @@ import android.support.v4.app.FragmentTabHost; * TabHost through fragments, using FragmentTabHost. */ public class FragmentTabs extends FragmentActivity { - FragmentTabHost mTabHost; + private FragmentTabHost mTabHost; @Override protected void onCreate(Bundle savedInstanceState) { @@ -45,16 +45,6 @@ public class FragmentTabs extends FragmentActivity { LoaderCustomSupport.AppListFragment.class, null); mTabHost.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"), LoaderThrottleSupport.ThrottledLoaderListFragment.class, null); - - if (savedInstanceState != null) { - mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); - } - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString("tab", mTabHost.getCurrentTabTag()); } } //END_INCLUDE(complete) diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsFragmentSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsFragmentSupport.java index d11975f38..68f06effd 100644 --- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsFragmentSupport.java +++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsFragmentSupport.java @@ -26,8 +26,7 @@ import android.view.View; import android.view.ViewGroup; public class FragmentTabsFragmentSupport extends Fragment { - FragmentTabHost mTabHost; - String mCurrentTabTag; + private FragmentTabHost mTabHost; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -44,35 +43,13 @@ public class FragmentTabsFragmentSupport extends Fragment { mTabHost.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"), LoaderThrottleSupport.ThrottledLoaderListFragment.class, null); - if (savedInstanceState != null) { - mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); - } return mTabHost; } - @Override - public void onViewStateRestored(Bundle savedInstanceState) { - super.onViewStateRestored(savedInstanceState); - if (savedInstanceState != null) { - mCurrentTabTag = savedInstanceState.getString("tab"); - } - mTabHost.setCurrentTabByTag(mCurrentTabTag); - } - @Override public void onDestroyView() { super.onDestroyView(); - // Need to remember the selected tab so that we can restore it if - // we later re-create the views. - mCurrentTabTag = mTabHost.getCurrentTabTag(); mTabHost = null; } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString("tab", mTabHost != null - ? mTabHost.getCurrentTabTag() : mCurrentTabTag); - } } //END_INCLUDE(complete)