1 /* 2 * Copyright (C) 2011 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.supportv4.app; 17 18 //BEGIN_INCLUDE(complete) 19 import java.util.HashMap; 20 21 import com.example.android.supportv4.R; 22 23 import android.content.Context; 24 import android.os.Bundle; 25 import android.support.v4.app.Fragment; 26 import android.support.v4.app.FragmentActivity; 27 import android.support.v4.app.FragmentTransaction; 28 import android.view.View; 29 import android.widget.TabHost; 30 31 /** 32 * This demonstrates how you can implement switching between the tabs of a 33 * TabHost through fragments. It uses a trick (see the code below) to allow 34 * the tabs to switch between fragments instead of simple views. 35 */ 36 public class FragmentTabs extends FragmentActivity { 37 TabHost mTabHost; 38 TabManager mTabManager; 39 40 @Override 41 protected void onCreate(Bundle savedInstanceState) { 42 super.onCreate(savedInstanceState); 43 44 setContentView(R.layout.fragment_tabs); 45 mTabHost = (TabHost)findViewById(android.R.id.tabhost); 46 mTabHost.setup(); 47 48 mTabManager = new TabManager(this, mTabHost, R.id.realtabcontent); 49 50 mTabManager.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"), 51 FragmentStackSupport.CountingFragment.class, null); 52 mTabManager.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"), 53 LoaderCursorSupport.CursorLoaderListFragment.class, null); 54 mTabManager.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"), 55 LoaderCustomSupport.AppListFragment.class, null); 56 mTabManager.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"), 57 LoaderThrottleSupport.ThrottledLoaderListFragment.class, null); 58 59 if (savedInstanceState != null) { 60 mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); 61 } 62 } 63 64 @Override 65 protected void onSaveInstanceState(Bundle outState) { 66 super.onSaveInstanceState(outState); 67 outState.putString("tab", mTabHost.getCurrentTabTag()); 68 } 69 70 /** 71 * This is a helper class that implements a generic mechanism for 72 * associating fragments with the tabs in a tab host. It relies on a 73 * trick. Normally a tab host has a simple API for supplying a View or 74 * Intent that each tab will show. This is not sufficient for switching 75 * between fragments. So instead we make the content part of the tab host 76 * 0dp high (it is not shown) and the TabManager supplies its own dummy 77 * view to show as the tab content. It listens to changes in tabs, and takes 78 * care of switch to the correct fragment shown in a separate content area 79 * whenever the selected tab changes. 80 */ 81 public static class TabManager implements TabHost.OnTabChangeListener { 82 private final FragmentActivity mActivity; 83 private final TabHost mTabHost; 84 private final int mContainerId; 85 private final HashMap<String, TabInfo> mTabs = new HashMap<String, TabInfo>(); 86 TabInfo mLastTab; 87 88 static final class TabInfo { 89 private final String tag; 90 private final Class<?> clss; 91 private final Bundle args; 92 private Fragment fragment; 93 94 TabInfo(String _tag, Class<?> _class, Bundle _args) { 95 tag = _tag; 96 clss = _class; 97 args = _args; 98 } 99 } 100 101 static class DummyTabFactory implements TabHost.TabContentFactory { 102 private final Context mContext; 103 104 public DummyTabFactory(Context context) { 105 mContext = context; 106 } 107 108 @Override 109 public View createTabContent(String tag) { 110 View v = new View(mContext); 111 v.setMinimumWidth(0); 112 v.setMinimumHeight(0); 113 return v; 114 } 115 } 116 117 public TabManager(FragmentActivity activity, TabHost tabHost, int containerId) { 118 mActivity = activity; 119 mTabHost = tabHost; 120 mContainerId = containerId; 121 mTabHost.setOnTabChangedListener(this); 122 } 123 124 public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) { 125 tabSpec.setContent(new DummyTabFactory(mActivity)); 126 String tag = tabSpec.getTag(); 127 128 TabInfo info = new TabInfo(tag, clss, args); 129 130 // Check to see if we already have a fragment for this tab, probably 131 // from a previously saved state. If so, deactivate it, because our 132 // initial state is that a tab isn't shown. 133 info.fragment = mActivity.getSupportFragmentManager().findFragmentByTag(tag); 134 if (info.fragment != null && !info.fragment.isDetached()) { 135 FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction(); 136 ft.detach(info.fragment); 137 ft.commit(); 138 } 139 140 mTabs.put(tag, info); 141 mTabHost.addTab(tabSpec); 142 } 143 144 @Override 145 public void onTabChanged(String tabId) { 146 TabInfo newTab = mTabs.get(tabId); 147 if (mLastTab != newTab) { 148 FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction(); 149 if (mLastTab != null) { 150 if (mLastTab.fragment != null) { 151 ft.detach(mLastTab.fragment); 152 } 153 } 154 if (newTab != null) { 155 if (newTab.fragment == null) { 156 newTab.fragment = Fragment.instantiate(mActivity, 157 newTab.clss.getName(), newTab.args); 158 ft.add(mContainerId, newTab.fragment, newTab.tag); 159 } else { 160 ft.attach(newTab.fragment); 161 } 162 } 163 164 mLastTab = newTab; 165 ft.commit(); 166 mActivity.getSupportFragmentManager().executePendingTransactions(); 167 } 168 } 169 } 170 } 171 //END_INCLUDE(complete) 172