在实际项目中我们我们其实经常看到上面(或者下面)是一个类似于tab标签的东西,下面是真正的内容区域,点击不同标签内容区域会显示不同的内容,以前用过一个TabHost的组件,现在过时了,大概是因为有了fragment,被FragmentTabHost取代了。闲言少叙,先看一下官方文档的描述,了解一个类的用法,看官方文档,是最快和最准确的
原来这个家伙来自于Android.support.v4.app这个包下,继承自 TabHost ,并且实现了 TabHost.OnTabChangeListener 接口。文档上也直接放了两个例子。一个是在Activity下包含多个fragment,注意这个activity是v4包下的 FragmentActivity,
package com.yangyu.mycustomtab02;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TabHost.TabSpec;
import android.widget.TextView;
/**
* @author yangyu
* 功能描述:自定义TabHost
*/
public class MainTabActivity extends FragmentActivity{
//定义FragmentTabHost对象
private FragmentTabHost mTabHost;
//定义一个布局
private LayoutInflater layoutInflater;
//定义数组来存放Fragment界面
private Class fragmentArray[] = {FragmentPage1.class,FragmentPage2.class,FragmentPage3.class,FragmentPage4.class,FragmentPage5.class};
//定义数组来存放按钮图片
private int mImageViewArray[] = {R.drawable.tab_home_btn,R.drawable.tab_message_btn,R.drawable.tab_selfinfo_btn,
R.drawable.tab_square_btn,R.drawable.tab_more_btn};
//Tab选项卡的文字
private String mTextviewArray[] = {"首页", "消息", "好友", "广场", "更多"};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_tab_layout);
initView();
}
/**
* 初始化组件
*/
private void initView(){
//实例化布局对象
layoutInflater = LayoutInflater.from(this);
//实例化TabHost对象,得到TabHost
mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
//得到fragment的个数
int count = fragmentArray.length;
for(int i = 0; i < count; i++){
//为每一个Tab按钮设置图标、文字和内容
TabSpec tabSpec = mTabHost.newTabSpec(mTextviewArray[i]).setIndicator(getTabItemView(i));
//将Tab按钮添加进Tab选项卡中
mTabHost.addTab(tabSpec, fragmentArray[i], null);
//设置Tab按钮的背景
mTabHost.getTabWidget().getChildAt(i).setBackgroundResource(R.drawable.selector_tab_background);
}
}
/**
* 给Tab按钮设置图标和文字
*/
private View getTabItemView(int index){
View view = layoutInflater.inflate(R.layout.tab_item_view, null);
ImageView imageView = (ImageView) view.findViewById(R.id.imageview);
imageView.setImageResource(mImageViewArray[index]);
TextView textView = (TextView) view.findViewById(R.id.textview);
textView.setText(mTextviewArray[index]);
return view;
}
}
注意: FragmentTabHost是v4包下的类,一定要写全包名和类名。
写完了布局文件,接着研究java代码,
mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
先把tabhost找到,也可以把context传进去直接new出来。
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
对tabhost做初始化的操作,但是在activity和在fragment里面这两句代码是不一样的,fragment的FragmentManager一定要写成 getChildFragmentManager(),说明是他子fragment的manager。
mTabHost.addTab(mTabHost.newTabSpec(“simple”).setIndicator(“Simple”),
FragmentStackSupport.CountingFragment.class, null);
然后添加4个Tab,其中 mTabHost.newTabSpec(“simple”)这个simple是该Tab的tag, setIndicator(“Simple”)是标签显示的label,有三个重载方法,
setIndicator(CharSequence label);
setIndicator(CharSequence label, Drawable icon);
setIndicator(View view)
从参数名字就可以看出来,就不多做解释,其中一和二是系统提供的布局,第三种可以自定义自己想要的view。
FragmentStackSupport.CountingFragment.class
是要添加的fragment字节码,最后一个参数是一个bundle类型的tag。
其实到这个地方已经大功告成。我们不需要add,replace等等一切对fragment的操作,FragmentTabHost非常强大,他会对所添加的fragment进行管理,保存栈信息和恢复栈信息等一切操作,比如我的fragment内部有三个子fragment,我退出该fragment的时候开启的是第二个子fragment,下次我再进入该fragment的时候依然会开启第二个子fragment,且看 FragmentTabHost源码中对保存,和恢复的操作:
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.curTab = getCurrentTabTag();
return ss;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState)state;
super.onRestoreInstanceState(ss.getSuperState());
setCurrentTabByTag(ss.curTab);
}
在该fragment退出的时候会自动执行 onSaveInstanceState()方法,把当前打开的fragment的TabTag通过 Parcelable的方式 记录下来,然后当再次进入到该fragment的时候会自动执行OnRestoreInstanceState(Parcelable state)方法,把之前保存的状态恢复,打开记录的TabTag对应的fragment
通过代码实际检验,即使退出的时候是打开的第二个fragment,但是再次进来的时候也会执行一遍第一个fragment的生命周期方法,主要是因为tabhost要有一个默认的打开界面。且看他的addTab方法
public void addTab(TabHost.TabSpec tabSpec, Class
package com.yangyu.mycustomtab02;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class FragmentPage1 extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_1, null);
}
}
其他4个一样
布局:
(1)这是main_tab_layout的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<FrameLayout
android:id="@+id/realtabcontent"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1" />
<android.support.v4.app.FragmentTabHost
android:id="@android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/maintab_toolbar_bg">
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0" />
</android.support.v4.app.FragmentTabHost>
</LinearLayout>
(2)这是tab_item_view的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="@+id/imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:padding="3dp"
android:src="@drawable/tab_home_btn">
</ImageView>
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="首页"
android:textSize="10sp"
android:textColor="#ffffff">
</TextView>
</LinearLayout>
(2)这是5个fragment的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView
android:id="@+id/imageview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitCenter"
android:src="@drawable/xianjian01" >
</ImageView>
</LinearLayout>
最后效果图: