Easy navigation and presentation are 2 main things that can make your software more user friendly. To achieve this we can combine TabHost widget and ViewPager LayoutManager together.
Scenario
The UI is consist of 3 tabs and 3 pages. Selecting each tab will automatically swipe to the corresponding page in the ViewPager. The other way around, swiping each page will result in the selection of the matching tab. Here I'm not going to discuss how to create tabs you can find so many tutorials on the net. The focus of this article is on how to use these 2 useful widgets together and how they can interact with each other.
Solution
Now, lets look at some code and see how we can implement the scenario. Here we have a MainActivity class. Apart from creating the necessary views and setting their properties in the overridden onCreate method pay attention to the 2 interfaces that this class has implemented. These are the listeners responsible to listening for the appropriate events that we are interested on.
public class MainActivity extends Activity implements OnTabChangeListener, OnPageChangeListener{
private TabHost host;
private ViewPager pager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
host = (TabHost)findViewById(android.R.id.tabhost);
pager = (ViewPager) findViewById(R.id.pager);
host.setup();
TabSpec spec = host.newTabSpec("tab1");
spec.setContent(R.id.tab1);
spec.setIndicator("First tab");
host.addTab(spec);
spec = host.newTabSpec("tab2");
spec.setContent(R.id.tab2);
spec.setIndicator("Second tab");
host.addTab(spec);
spec = host.newTabSpec("tab3");
spec.setContent(R.id.tab3);
spec.setIndicator("Third tab");
host.addTab(spec);
pager.setAdapter(new MyPagerAdapter(this));
pager.setOnPageChangeListener(this);
host.setOnTabChangedListener(this);
}
@Override
public void onTabChanged(String tabId){
int pageNumber = 0;
if(tabId.equals("tab1")){
pageNumber = 0;
} else if(tabId.equals("tab2")){
pageNumber = 1;
} else{
pageNumber = 2;
}
pager.setCurrentItem(pageNumber);
}
@Override
public void onPageSelected(int pageNumber) {
host.setCurrentTab(pageNumber);
}
If you select a tab or swipe a page you can get notified by these listeners methods.As you can see in the above snippet in each method we are instructing the other one to show the appropriate tab or page. For example, when a tab is selected the tag string we assigned to its TabSpec is passed to the onTabChanged method. By comparing the strings we can find out which tab was selected and accordingly set the corresponding page and instructing the pager to set its current item by setCurrentItem which accepts the page number.
The content of our view is read from the file below. If you take a look you can see that each TabSpec is constructed using a FrameLayout.
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</TabWidget>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="@+id/tab1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
<FrameLayout
android:id="@+id/tab2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
<FrameLayout
android:id="@+id/tab3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</FrameLayout>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</TabHost>
Finally, here is our PageAdapter feeding our ViewPager. for the sake of simplicity each page is consisted of only one TextView.
public class MyPagerAdapter extends PagerAdapter {
private Context ctx;
public MyPagerAdapter(Context ctx){
this.ctx = ctx;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
TextView tView = new TextView(ctx);
position++;
tView.setText("Page number: " + position);
tView.setTextColor(Color.RED);
tView.setTextSize(20);
container.addView(tView);
return tView;
}
@Override
public int getCount() {
return 3;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return (view == object);
}
}