1aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn/*
2aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Copyright (C) 2011 The Android Open Source Project
3aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn *
4aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
5aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * you may not use this file except in compliance with the License.
6aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * You may obtain a copy of the License at
7aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn *
8aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
9aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn *
10aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
11aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
12aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * See the License for the specific language governing permissions and
14aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * limitations under the License.
15aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */
16aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornpackage com.example.android.supportv4.app;
17aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
18aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.content.Context;
19aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.os.Bundle;
20aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.support.v4.app.Fragment;
21aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.support.v4.app.FragmentActivity;
22aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.support.v4.app.FragmentPagerAdapter;
23aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.support.v4.view.ViewPager;
24aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.view.View;
25865abe20dd1a639efe9a013240e61613a52b6648Dianne Hackbornimport android.view.ViewGroup;
26aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornimport android.widget.TabHost;
27865abe20dd1a639efe9a013240e61613a52b6648Dianne Hackbornimport android.widget.TabWidget;
28aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
299c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikasimport com.example.android.supportv4.R;
309c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas
31560d99a32ec737d928cbca48a0fc2235181fe922Adam Powellimport java.util.ArrayList;
32560d99a32ec737d928cbca48a0fc2235181fe922Adam Powell
33aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn/**
34aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * Demonstrates combining a TabHost with a ViewPager to implement a tab UI
35aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * that switches between tabs and also allows the user to perform horizontal
36aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn * flicks to move between the tabs.
37aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn */
38aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackbornpublic class FragmentTabsPager extends FragmentActivity {
39aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    TabHost mTabHost;
40aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    ViewPager  mViewPager;
41aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    TabsAdapter mTabsAdapter;
42aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
43aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    @Override
44aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    protected void onCreate(Bundle savedInstanceState) {
45aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        super.onCreate(savedInstanceState);
46aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
47aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        setContentView(R.layout.fragment_tabs_pager);
48aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        mTabHost = (TabHost)findViewById(android.R.id.tabhost);
49aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        mTabHost.setup();
50aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
51aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        mViewPager = (ViewPager)findViewById(R.id.pager);
52aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
53aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        mTabsAdapter = new TabsAdapter(this, mTabHost, mViewPager);
54aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
55aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        mTabsAdapter.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
56aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                FragmentStackSupport.CountingFragment.class, null);
57aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        mTabsAdapter.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
58aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                LoaderCursorSupport.CursorLoaderListFragment.class, null);
59aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        mTabsAdapter.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
60aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                LoaderCustomSupport.AppListFragment.class, null);
61aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        mTabsAdapter.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
62aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);
63aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
64aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        if (savedInstanceState != null) {
65aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
66aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
67aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    }
68aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
69aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    @Override
70aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    protected void onSaveInstanceState(Bundle outState) {
71aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        super.onSaveInstanceState(outState);
72aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        outState.putString("tab", mTabHost.getCurrentTabTag());
73aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    }
74aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
75aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    /**
76aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * This is a helper class that implements the management of tabs and all
77aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * details of connecting a ViewPager with associated TabHost.  It relies on a
78aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * trick.  Normally a tab host has a simple API for supplying a View or
79aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * Intent that each tab will show.  This is not sufficient for switching
80aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * between pages.  So instead we make the content part of the tab host
81aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
82aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * view to show as the tab content.  It listens to changes in tabs, and takes
83aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * care of switch to the correct paged in the ViewPager whenever the selected
84aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     * tab changes.
85aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn     */
86aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    public static class TabsAdapter extends FragmentPagerAdapter
87aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
88aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        private final Context mContext;
89aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        private final TabHost mTabHost;
90aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        private final ViewPager mViewPager;
91aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
92aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
93aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        static final class TabInfo {
94aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            private final String tag;
95aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            private final Class<?> clss;
96aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            private final Bundle args;
97aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
98aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            TabInfo(String _tag, Class<?> _class, Bundle _args) {
99aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                tag = _tag;
100aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                clss = _class;
101aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                args = _args;
102aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
103aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
104aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
105aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        static class DummyTabFactory implements TabHost.TabContentFactory {
106aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            private final Context mContext;
107aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
108aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            public DummyTabFactory(Context context) {
109aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                mContext = context;
110aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
111aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
112aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            @Override
113aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            public View createTabContent(String tag) {
114aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                View v = new View(mContext);
115aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                v.setMinimumWidth(0);
116aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                v.setMinimumHeight(0);
117aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn                return v;
118aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            }
119aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
120aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
121aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager) {
122aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            super(activity.getSupportFragmentManager());
123aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mContext = activity;
124aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mTabHost = tabHost;
125aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mViewPager = pager;
126aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mTabHost.setOnTabChangedListener(this);
127aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mViewPager.setAdapter(this);
1289c76e9550ada0475f1c750e5672128630d2a028cAurimas Liutikas            mViewPager.addOnPageChangeListener(this);
129aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
130aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
131aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
132aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            tabSpec.setContent(new DummyTabFactory(mContext));
133aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            String tag = tabSpec.getTag();
134aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
135aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            TabInfo info = new TabInfo(tag, clss, args);
136aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mTabs.add(info);
137aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mTabHost.addTab(tabSpec);
138aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            notifyDataSetChanged();
139aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
140aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
141aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override
142aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public int getCount() {
143aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            return mTabs.size();
144aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
145aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
146aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override
147aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public Fragment getItem(int position) {
148aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            TabInfo info = mTabs.get(position);
149aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            return Fragment.instantiate(mContext, info.clss.getName(), info.args);
150aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
151aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
152aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override
153aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public void onTabChanged(String tabId) {
154aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            int position = mTabHost.getCurrentTab();
155aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mViewPager.setCurrentItem(position);
156aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
157aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
158aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override
159aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
160aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
161aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn
162aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        @Override
163aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        public void onPageSelected(int position) {
164865abe20dd1a639efe9a013240e61613a52b6648Dianne Hackborn            // Unfortunately when TabHost changes the current tab, it kindly
165865abe20dd1a639efe9a013240e61613a52b6648Dianne Hackborn            // also takes care of putting focus on it when not in touch mode.
166865abe20dd1a639efe9a013240e61613a52b6648Dianne Hackborn            // The jerk.
167865abe20dd1a639efe9a013240e61613a52b6648Dianne Hackborn            // This hack tries to prevent this from pulling focus out of our
168865abe20dd1a639efe9a013240e61613a52b6648Dianne Hackborn            // ViewPager.
169865abe20dd1a639efe9a013240e61613a52b6648Dianne Hackborn            TabWidget widget = mTabHost.getTabWidget();
170865abe20dd1a639efe9a013240e61613a52b6648Dianne Hackborn            int oldFocusability = widget.getDescendantFocusability();
171865abe20dd1a639efe9a013240e61613a52b6648Dianne Hackborn            widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
172aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn            mTabHost.setCurrentTab(position);
173865abe20dd1a639efe9a013240e61613a52b6648Dianne Hackborn            widget.setDescendantFocusability(oldFocusability);
174aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn        }
175560d99a32ec737d928cbca48a0fc2235181fe922Adam Powell
176560d99a32ec737d928cbca48a0fc2235181fe922Adam Powell        @Override
177560d99a32ec737d928cbca48a0fc2235181fe922Adam Powell        public void onPageScrollStateChanged(int state) {
178560d99a32ec737d928cbca48a0fc2235181fe922Adam Powell        }
179aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn    }
180aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn}
181