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 import com.example.android.supportv4.R; 19 20 import android.content.Context; 21 import android.os.Bundle; 22 import android.support.v4.app.Fragment; 23 import android.support.v4.app.FragmentActivity; 24 import android.support.v4.app.FragmentPagerAdapter; 25 import android.support.v4.view.ViewPager; 26 import android.view.View; 27 import android.view.ViewGroup; 28 import android.widget.TabHost; 29 import android.widget.TabWidget; 30 31 import java.util.ArrayList; 32 33 /** 34 * Demonstrates combining a TabHost with a ViewPager to implement a tab UI 35 * that switches between tabs and also allows the user to perform horizontal 36 * flicks to move between the tabs. 37 */ 38 public class FragmentTabsPager extends FragmentActivity { 39 TabHost mTabHost; 40 ViewPager mViewPager; 41 TabsAdapter mTabsAdapter; 42 43 @Override 44 protected void onCreate(Bundle savedInstanceState) { 45 super.onCreate(savedInstanceState); 46 47 setContentView(R.layout.fragment_tabs_pager); 48 mTabHost = (TabHost)findViewById(android.R.id.tabhost); 49 mTabHost.setup(); 50 51 mViewPager = (ViewPager)findViewById(R.id.pager); 52 53 mTabsAdapter = new TabsAdapter(this, mTabHost, mViewPager); 54 55 mTabsAdapter.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"), 56 FragmentStackSupport.CountingFragment.class, null); 57 mTabsAdapter.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"), 58 LoaderCursorSupport.CursorLoaderListFragment.class, null); 59 mTabsAdapter.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"), 60 LoaderCustomSupport.AppListFragment.class, null); 61 mTabsAdapter.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"), 62 LoaderThrottleSupport.ThrottledLoaderListFragment.class, null); 63 64 if (savedInstanceState != null) { 65 mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); 66 } 67 } 68 69 @Override 70 protected void onSaveInstanceState(Bundle outState) { 71 super.onSaveInstanceState(outState); 72 outState.putString("tab", mTabHost.getCurrentTabTag()); 73 } 74 75 /** 76 * This is a helper class that implements the management of tabs and all 77 * details of connecting a ViewPager with associated TabHost. It relies on a 78 * trick. Normally a tab host has a simple API for supplying a View or 79 * Intent that each tab will show. This is not sufficient for switching 80 * between pages. So instead we make the content part of the tab host 81 * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy 82 * view to show as the tab content. It listens to changes in tabs, and takes 83 * care of switch to the correct paged in the ViewPager whenever the selected 84 * tab changes. 85 */ 86 public static class TabsAdapter extends FragmentPagerAdapter 87 implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener { 88 private final Context mContext; 89 private final TabHost mTabHost; 90 private final ViewPager mViewPager; 91 private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); 92 93 static final class TabInfo { 94 private final String tag; 95 private final Class<?> clss; 96 private final Bundle args; 97 98 TabInfo(String _tag, Class<?> _class, Bundle _args) { 99 tag = _tag; 100 clss = _class; 101 args = _args; 102 } 103 } 104 105 static class DummyTabFactory implements TabHost.TabContentFactory { 106 private final Context mContext; 107 108 public DummyTabFactory(Context context) { 109 mContext = context; 110 } 111 112 @Override 113 public View createTabContent(String tag) { 114 View v = new View(mContext); 115 v.setMinimumWidth(0); 116 v.setMinimumHeight(0); 117 return v; 118 } 119 } 120 121 public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager) { 122 super(activity.getSupportFragmentManager()); 123 mContext = activity; 124 mTabHost = tabHost; 125 mViewPager = pager; 126 mTabHost.setOnTabChangedListener(this); 127 mViewPager.setAdapter(this); 128 mViewPager.setOnPageChangeListener(this); 129 } 130 131 public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) { 132 tabSpec.setContent(new DummyTabFactory(mContext)); 133 String tag = tabSpec.getTag(); 134 135 TabInfo info = new TabInfo(tag, clss, args); 136 mTabs.add(info); 137 mTabHost.addTab(tabSpec); 138 notifyDataSetChanged(); 139 } 140 141 @Override 142 public int getCount() { 143 return mTabs.size(); 144 } 145 146 @Override 147 public Fragment getItem(int position) { 148 TabInfo info = mTabs.get(position); 149 return Fragment.instantiate(mContext, info.clss.getName(), info.args); 150 } 151 152 @Override 153 public void onTabChanged(String tabId) { 154 int position = mTabHost.getCurrentTab(); 155 mViewPager.setCurrentItem(position); 156 } 157 158 @Override 159 public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 160 } 161 162 @Override 163 public void onPageSelected(int position) { 164 // Unfortunately when TabHost changes the current tab, it kindly 165 // also takes care of putting focus on it when not in touch mode. 166 // The jerk. 167 // This hack tries to prevent this from pulling focus out of our 168 // ViewPager. 169 TabWidget widget = mTabHost.getTabWidget(); 170 int oldFocusability = widget.getDescendantFocusability(); 171 widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 172 mTabHost.setCurrentTab(position); 173 widget.setDescendantFocusability(oldFocusability); 174 } 175 176 @Override 177 public void onPageScrollStateChanged(int state) { 178 } 179 } 180 } 181