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