理解
它是一个带有页签的界面。可以分成两部分,一部分是界面,一部分是页签。如果要使用TabHost,那么Activity必须继承TabActivity。可以通过TabHost host = getTabHost();获取TabHost。
页签(TabSpec)
通过TabSpec控制。对于一个页签,它应该具有三个部分:页签的界面、第二页签关联的界面、页签的tag(相当于id,是唯一的)。
获取与添加
TabSpec spec = host.newTabSpec("tag");//获取一个TabSpec,其中tag为TabSpec的tag
host.addTab(spec);//将TabSpec添加到对应的TabHost中
方法说明
第一组是设置页签的界面:
setIndicator(CharSequence label)
setIndicator(CharSequence label, Drawable icon)
setIndicator(View view)
在系统默认情况下,一个页签是由一个icon与文字说明(label)组成的。第一个方法是设置label(此时没有icon),第二个方法是设置label与icon。而第三个方法就是完全自定义了页签的样式,使用自定义页签界面后可以为该页签设置选择器,从而形成选中和未选中两个不同的样式。
第二组是设置页签所关联的界面:
setContent(int viewId)
setContent(TabContentFactory contentFactory)
setContent(Intent intent)
第一个方法是设置关联的view对应的id。
第三个方法intent,这样点击该条目时就会执行相应的intent。例如:
TabSpec spec2 = host.newTabSpec("tab2").setIndicator("tab2",
getResources().getDrawable(R.drawable.ic_launcher));
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
spec2.setContent(intent);
host.addTab(spec2);
那么在点击第三个条目时,就会打开SecondActivity。这也使得tabhost和多个activity联用成为现实。
TabContentFactory
该接口中只有一个方法View createTabContent(String tag),它的主要作用是产生一个跟相应页签关联的界面。因此createTabContent()返回的是一个View。如: public View createTabContent(String tag) {
if ("tab1".equals(tag)) {//当页签的tag为"tab1"时返回一个TextView
TextView tv = new TextView(this);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
tv.setBackgroundColor(Color.rgb(0xff, 0, 0xaa));
tv.setTag(lp);
tv.setText(tag);
return tv;
} else if ("tab2".equals(tag)) {//当页签的tag为"tab2"时返回一个ImageView
ImageView iv = new ImageView(this);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
iv.setLayoutParams(lp);
iv.setImageResource(R.drawable.ic_launcher);
return iv;
} else {//否则返回一个而已生成的界面
return View.inflate(this, R.layout.item, null);
}
}
界面
对于TabHost,所有的界面必须放在一个FrameLayout中。也可以认为该FrameLayout是一个盛放界面的容器,类似于使用Fragment需要一个ViewGroup来盛放相应的界面一样。当然,如果TabSpec.setContent()时传入的是一个intent或者TabContentFactory,此时的界面也不必在FrameLayout中。
示例
系统默认的TabHost布局
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TabHost host = getTabHost();
LayoutInflater.from(this).inflate(R.layout.only_text,
host.getTabContentView(), true);//把指定的FrameLayout设置成TabHost的界面
host.addTab(host.newTabSpec("tab1")
.setIndicator("tab1",getResources().getDrawable(R.drawable.ic_launcher))
.setContent(R.id.view1));<pre name="code" class="java"><span style="white-space:pre"> </span>TabSpec spec2 = host.newTabSpec("tab2").setIndicator("tab2",
getResources().getDrawable(R.drawable.ic_launcher));
spec2.setContent(R.id.view2);
host.addTab(spec2);<pre name="code" class="java"> host.addTab(host.newTabSpec("tab3")
.setIndicator(View.inflate(this, R.layout.item, null)).setContent(R.id.view3));
}
从上面的例子中看出并没有使用setContentView(),此时采用的就是系统默认的TabHost的样式。在添加TabSpec的时,所有的content(R.id.view1,R.id.view2,R.id.view3)都是在R.layout.only_text中。
自定义整个TabHost的布局
布局
<?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="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
>
</TabWidget>
<FrameLayout
android:layout_above="@android:id/tabs"
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:background="#ffff00"
android:id="@+id/content1"
android:text="第一个界面"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:background="#ffaa00"
android:id="@+id/content2"
android:text="第二个界面"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:background="#ff6600"
android:id="@+id/content3"
android:text="第三个界面"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</RelativeLayout>
</TabHost>
TabWidget的id必须是@android:id/tabs,它就是用来盛放页签的容器。它是必须有的。
FrameLayout的id必须是@android:id/tabcontent。它就是有来盛放界面的。也是必须有的。
TabHost的id是@android:id/tabhost。
Activity中代码
public class MainActivity extends TabActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.animation_3);
TabHost host = getTabHost();
TabSpec spec1 = host.newTabSpec("tag1").setIndicator("未接电话", getResources().getDrawable(R.drawable.a1)).setContent(R.id.content1);
host.addTab(spec1);
TabSpec spec2 = host.newTabSpec("tag2").setIndicator("已接电话", getResources().getDrawable(R.drawable.a1)).setContent(R.id.content2);
host.addTab(spec2);
TabSpec spec3 = host.newTabSpec("tag3").setIndicator("已拨电话", getResources().getDrawable(R.drawable.a1)).setContent(R.id.content3);
host.addTab(spec3);
}
}
效果图:
常见问题
水平滚动页签
比较上面两个例子可以发现自定义的时候,页签的位置是灵活的,而使用系统的位置将是固定的。而且,使用自定义布局的时候,当页签过多时,可以水平滚动面签,只需要在TabWidget外包一层HorizontalScrollView即可。方法如下:
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none">
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</HorizontalScrollView>