1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.example.android.apis.app; 17 18 import java.util.ArrayList; 19 20 import com.example.android.apis.R; 21 22 import android.app.Fragment; 23 import android.app.FragmentManager; 24 import android.app.FragmentTransaction; 25 import android.content.Context; 26 import android.os.Bundle; 27 import android.view.LayoutInflater; 28 import android.view.View; 29 import android.view.ViewGroup; 30 import android.widget.TabHost; 31 32 /** 33 * Sample fragment that contains tabs of other fragments. 34 */ 35 public class FragmentTabsFragment extends Fragment { 36 TabManager mTabManager; 37 38 @Override onCreate(Bundle savedInstanceState)39 public void onCreate(Bundle savedInstanceState) { 40 super.onCreate(savedInstanceState); 41 mTabManager = new TabManager(getActivity(), getChildFragmentManager(), 42 R.id.realtabcontent); 43 } 44 45 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)46 public View onCreateView(LayoutInflater inflater, ViewGroup container, 47 Bundle savedInstanceState) { 48 View v = inflater.inflate(R.layout.fragment_tabs_fragment, container, false); 49 TabHost host = mTabManager.handleCreateView(v); 50 51 mTabManager.addTab(host.newTabSpec("result").setIndicator("Result"), 52 FragmentReceiveResult.ReceiveResultFragment.class, null); 53 mTabManager.addTab(host.newTabSpec("contacts").setIndicator("Contacts"), 54 LoaderCursor.CursorLoaderListFragment.class, null); 55 mTabManager.addTab(host.newTabSpec("apps").setIndicator("Apps"), 56 LoaderCustom.AppListFragment.class, null); 57 mTabManager.addTab(host.newTabSpec("throttle").setIndicator("Throttle"), 58 LoaderThrottle.ThrottledLoaderListFragment.class, null); 59 60 return v; 61 } 62 63 @Override onViewStateRestored(Bundle savedInstanceState)64 public void onViewStateRestored(Bundle savedInstanceState) { 65 super.onViewStateRestored(savedInstanceState); 66 mTabManager.handleViewStateRestored(savedInstanceState); 67 } 68 69 @Override onDestroyView()70 public void onDestroyView() { 71 super.onDestroyView(); 72 mTabManager.handleDestroyView(); 73 } 74 75 @Override onSaveInstanceState(Bundle outState)76 public void onSaveInstanceState(Bundle outState) { 77 super.onSaveInstanceState(outState); 78 mTabManager.handleSaveInstanceState(outState); 79 } 80 81 /** 82 * This is a helper class that implements a generic mechanism for 83 * associating fragments with the tabs in a tab host. DO NOT USE THIS. 84 * If you want tabs in a fragment, use the support v13 library's 85 * FragmentTabHost class, which takes care of all of this for you (in 86 * a simpler way even). 87 */ 88 public static class TabManager implements TabHost.OnTabChangeListener { 89 private final Context mContext; 90 private final FragmentManager mManager; 91 private final int mContainerId; 92 private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); 93 private TabHost mTabHost; 94 private TabInfo mLastTab; 95 private boolean mInitialized; 96 private String mCurrentTabTag; 97 98 static final class TabInfo { 99 private final String tag; 100 private final Class<?> clss; 101 private final Bundle args; 102 private Fragment fragment; 103 TabInfo(String _tag, Class<?> _class, Bundle _args)104 TabInfo(String _tag, Class<?> _class, Bundle _args) { 105 tag = _tag; 106 clss = _class; 107 args = _args; 108 } 109 } 110 111 static class DummyTabFactory implements TabHost.TabContentFactory { 112 private final Context mContext; 113 DummyTabFactory(Context context)114 public DummyTabFactory(Context context) { 115 mContext = context; 116 } 117 118 @Override createTabContent(String tag)119 public View createTabContent(String tag) { 120 View v = new View(mContext); 121 v.setMinimumWidth(0); 122 v.setMinimumHeight(0); 123 return v; 124 } 125 } 126 TabManager(Context context, FragmentManager manager, int containerId)127 public TabManager(Context context, FragmentManager manager, int containerId) { 128 mContext = context; 129 mManager = manager; 130 mContainerId = containerId; 131 } 132 handleCreateView(View root)133 public TabHost handleCreateView(View root) { 134 if (mTabHost != null) { 135 throw new IllegalStateException("TabHost already set"); 136 } 137 mTabHost = (TabHost)root.findViewById(android.R.id.tabhost); 138 mTabHost.setup(); 139 mTabHost.setOnTabChangedListener(this); 140 return mTabHost; 141 } 142 addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args)143 public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) { 144 tabSpec.setContent(new DummyTabFactory(mContext)); 145 String tag = tabSpec.getTag(); 146 TabInfo info = new TabInfo(tag, clss, args); 147 mTabs.add(info); 148 mTabHost.addTab(tabSpec); 149 } 150 handleViewStateRestored(Bundle savedInstanceState)151 public void handleViewStateRestored(Bundle savedInstanceState) { 152 if (savedInstanceState != null) { 153 mCurrentTabTag = savedInstanceState.getString("tab"); 154 } 155 mTabHost.setCurrentTabByTag(mCurrentTabTag); 156 157 String currentTab = mTabHost.getCurrentTabTag(); 158 159 // Go through all tabs and make sure their fragments match 160 // the correct state. 161 FragmentTransaction ft = null; 162 for (int i=0; i<mTabs.size(); i++) { 163 TabInfo tab = mTabs.get(i); 164 tab.fragment = mManager.findFragmentByTag(tab.tag); 165 if (tab.fragment != null && !tab.fragment.isDetached()) { 166 if (tab.tag.equals(currentTab)) { 167 // The fragment for this tab is already there and 168 // active, and it is what we really want to have 169 // as the current tab. Nothing to do. 170 mLastTab = tab; 171 } else { 172 // This fragment was restored in the active state, 173 // but is not the current tab. Deactivate it. 174 if (ft == null) { 175 ft = mManager.beginTransaction(); 176 } 177 ft.detach(tab.fragment); 178 } 179 } 180 } 181 182 // We are now ready to go. Make sure we are switched to the 183 // correct tab. 184 mInitialized = true; 185 ft = doTabChanged(currentTab, ft); 186 if (ft != null) { 187 ft.commit(); 188 mManager.executePendingTransactions(); 189 } 190 } 191 handleDestroyView()192 public void handleDestroyView() { 193 mCurrentTabTag = mTabHost.getCurrentTabTag(); 194 mTabHost = null; 195 mTabs.clear(); 196 mInitialized = false; 197 } 198 handleSaveInstanceState(Bundle outState)199 public void handleSaveInstanceState(Bundle outState) { 200 outState.putString("tab", mTabHost != null 201 ? mTabHost.getCurrentTabTag() : mCurrentTabTag); 202 } 203 204 @Override onTabChanged(String tabId)205 public void onTabChanged(String tabId) { 206 if (!mInitialized) { 207 return; 208 } 209 FragmentTransaction ft = doTabChanged(tabId, null); 210 if (ft != null) { 211 ft.commit(); 212 } 213 } 214 doTabChanged(String tabId, FragmentTransaction ft)215 private FragmentTransaction doTabChanged(String tabId, FragmentTransaction ft) { 216 TabInfo newTab = null; 217 for (int i=0; i<mTabs.size(); i++) { 218 TabInfo tab = mTabs.get(i); 219 if (tab.tag.equals(tabId)) { 220 newTab = tab; 221 } 222 } 223 if (newTab == null) { 224 throw new IllegalStateException("No tab known for tag " + tabId); 225 } 226 if (mLastTab != newTab) { 227 if (ft == null) { 228 ft = mManager.beginTransaction(); 229 } 230 if (mLastTab != null) { 231 if (mLastTab.fragment != null) { 232 ft.detach(mLastTab.fragment); 233 } 234 } 235 if (newTab != null) { 236 if (newTab.fragment == null) { 237 newTab.fragment = Fragment.instantiate(mContext, 238 newTab.clss.getName(), newTab.args); 239 ft.add(mContainerId, newTab.fragment, newTab.tag); 240 } else { 241 ft.attach(newTab.fragment); 242 } 243 } 244 245 mLastTab = newTab; 246 } 247 return ft; 248 } 249 } 250 } 251 //END_INCLUDE(complete) 252