1 /* 2 * Copyright 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 17 package com.example.android.tabcompat.lib; 18 19 import android.content.Context; 20 import android.os.Bundle; 21 import android.support.v4.app.Fragment; 22 import android.support.v4.app.FragmentActivity; 23 import android.support.v4.app.FragmentTransaction; 24 import android.view.View; 25 import android.widget.TabHost; 26 import android.widget.TabHost.TabSpec; 27 28 import java.util.HashMap; 29 30 /** 31 * This is a helper class to build tabs on pre-Honeycomb. Call {@link 32 * TabCompatActivity#getTabHelper()} to get the generic instance for 33 * compatibility with other versions. 34 * 35 * It implements a generic mechanism for associating fragments with the tabs in a tab host. It 36 * relies on a trick: Normally a tab host has a simple API for supplying a View or Intent that each 37 * tab will show. This is not sufficient for switching between fragments. So instead we make the 38 * content part of the tab host 0dp high (it is not shown) and this supplies its own dummy view to 39 * show as the tab content. It listens to changes in tabs, then passes the event back to the tab's 40 * callback interface so the activity can take care of switching to the correct fragment. 41 */ 42 public class TabHelperEclair extends TabHelper implements TabHost.OnTabChangeListener { 43 44 private final HashMap<String, CompatTab> mTabs = new HashMap<String, CompatTab>(); 45 private TabHost mTabHost; 46 CompatTabListener mCallback; 47 CompatTab mLastTab; 48 TabHelperEclair(FragmentActivity activity)49 protected TabHelperEclair(FragmentActivity activity) { 50 super(activity); 51 mActivity = activity; 52 } 53 54 @Override setUp()55 protected void setUp() { 56 if (mTabHost == null) { 57 mTabHost = (TabHost) mActivity.findViewById(android.R.id.tabhost); 58 mTabHost.setup(); 59 mTabHost.setOnTabChangedListener(this); 60 } 61 } 62 63 @Override addTab(CompatTab tab)64 public void addTab(CompatTab tab) { 65 String tag = tab.getTag(); 66 TabSpec spec; 67 68 if (tab.getIcon() != null) { 69 spec = mTabHost.newTabSpec(tag).setIndicator(tab.getText(), tab.getIcon()); 70 } else { 71 spec = mTabHost.newTabSpec(tag).setIndicator(tab.getText()); 72 } 73 74 spec.setContent(new DummyTabFactory(mActivity)); 75 76 // Check to see if we already have a fragment for this tab, probably 77 // from a previously saved state. If so, deactivate it, because our 78 // initial state is that a tab isn't shown. 79 80 Fragment fragment = mActivity.getSupportFragmentManager().findFragmentByTag(tag); 81 tab.setFragment(fragment); 82 83 if (fragment != null && !fragment.isDetached()) { 84 FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction(); 85 ft.detach(fragment); 86 ft.commit(); 87 } 88 89 mTabs.put(tag, tab); 90 mTabHost.addTab(spec); 91 } 92 93 /** 94 * Converts the basic "tab changed" event for TabWidget into the three possible events for 95 * CompatTabListener: selected, unselected, reselected. 96 */ 97 @Override onTabChanged(String tabId)98 public void onTabChanged(String tabId) { 99 CompatTab newTab = mTabs.get(tabId); 100 FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction(); 101 102 if (mLastTab != newTab) { 103 if (mLastTab != null) { 104 if (mLastTab.getFragment() != null) { 105 // Pass the unselected event back to the tab's CompatTabListener 106 mLastTab.getCallback().onTabUnselected(mLastTab, ft); 107 } 108 } 109 if (newTab != null) { 110 // Pass the selected event back to the tab's CompatTabListener 111 newTab.getCallback().onTabSelected(newTab, ft); 112 } 113 114 mLastTab = newTab; 115 } else { 116 // Pass the re-selected event back to the tab's CompatTabListener 117 newTab.getCallback().onTabReselected(newTab, ft); 118 } 119 120 ft.commit(); 121 mActivity.getSupportFragmentManager().executePendingTransactions(); 122 } 123 124 @Override onSaveInstanceState(Bundle outState)125 protected void onSaveInstanceState(Bundle outState) { 126 // Save and restore the selected tab for rotations/restarts. 127 outState.putString("tab", mTabHost.getCurrentTabTag()); 128 } 129 130 @Override onRestoreInstanceState(Bundle savedInstanceState)131 protected void onRestoreInstanceState(Bundle savedInstanceState) { 132 if (savedInstanceState != null) { 133 mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); 134 } 135 } 136 137 /** 138 * Backwards-compatibility mumbo jumbo 139 */ 140 static class DummyTabFactory implements TabHost.TabContentFactory { 141 142 private final Context mContext; 143 DummyTabFactory(Context context)144 public DummyTabFactory(Context context) { 145 mContext = context; 146 } 147 148 @Override createTabContent(String tag)149 public View createTabContent(String tag) { 150 View v = new View(mContext); 151 v.setMinimumWidth(0); 152 v.setMinimumHeight(0); 153 return v; 154 } 155 } 156 } 157