在上一篇文章“ TabHost 用法”中我们介绍了通过TabHost实现标签页效果。但是在实际项目中我们可能更希望定义自己的 Tab标签 样式使界面效果更佳。既然不能改变系统的 Tab 样式,那么我们可以选择隐藏系统的东西,使用自己定义的东西(这种方式很好用,以后会详细介绍)。反编译新浪微博的项目后会发现,他们在布局中隐藏了 TabWidget 即 Tab 标签而使用一组 RadioButton 来代替。既然是自己定义的,那肯定是可以自己决定显示样式了,那我们的问题也就解决了。 这里我使用的是“ TabHost 用法—两种实现方式”一文种提到的第二种实现方式,继承 Activity 来使用 TabHost 的。先把代码贴上来(红色字体部分为修改或添加的代码)。
TabHostActivity.java
public class TabHostActivity extends Activity implements
OnCheckedChangeListener {
private TabHost tabHost ;
private Intent certificateIntent ;
private Intent feeIntent ;
private Intent scoreIntent ;
private Intent studyIntent ;
private Intent moreIntent ;
@Override
public void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout. tab );
// tabHost = getTabHost();
tabHost = (TabHost) findViewById(R.id. my_tabhost );
LocalActivityManager groupActivity =
new LocalActivityManager( this , false );
groupActivity.dispatchCreate(savedInstanceState);
tabHost .setup(groupActivity);
initIntent();
addSpec();
((RadioGroup) findViewById(R.id.tab_radiogroup ))
.set OnCheckedChangeListener (this );
}
/**
* 初始化各个 tab 标签对应的 intent
*/
private void initIntent() {
studyIntent = new Intent( this , StudyActivity. class );
scoreIntent = new Intent( this , ScoreActivity. class );
feeIntent = new Intent( this , FeeActivity. class );
certificateIntent = new Intent( this , CertificateActivity. class );
moreIntent = new Intent( this , MoreActivity. class );
}
/**
* 为 tabHost 添加各个标签项
*/
private void addSpec() {
tabHost .addTab( this .buildTagSpec( "tab_study" , R.string. study_progress ,
R.drawable. account01 , studyIntent ));
tabHost .addTab( this .buildTagSpec( "tab_score" , R.string. test_score ,
R.drawable. account02 , scoreIntent ));
tabHost .addTab( this .buildTagSpec( "tab_fee" , R.string. fee_pay ,
R.drawable. account03 , feeIntent ));
tabHost .addTab( this .buildTagSpec( "tab_certificate" ,
R.string. certificate_grant , R.drawable. account04 ,
certificateIntent ));
tabHost .addTab( this .buildTagSpec( "tab_more" , R.string. more ,
R.drawable. account05 , moreIntent ));
}
/**
* 自定义创建标签项的方法
* @param tagName 标签标识
* @param tagLable 标签文字
* @param icon 标签图标
* @param content 标签对应的内容
* @return
*/
private TabHost.TabSpec buildTagSpec(String tagName, int tagLable,
int icon, Intent content) {
return tabHost
.newTabSpec(tagName)
.setIndicator(getResources().getString(tagLable),
getResources().getDrawable(icon)).setContent(content);
}
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch (checkedId) {
case R.id.radio_button_study :
tabHost.setCurrentTabByTag("tab_study");
break ;
case R.id.radio_button_score :
tabHost.setCurrentTabByTag("tab_score");
break ;
case R.id.radio_button_certificate :
tabHost.setCurrentTabByTag("tab_certificate");
break ;
case R.id.radio_button_fee :
tabHost.setCurrentTabByTag("tab_fee");
break ;
case R.id.radio_button_more :
tabHost.setCurrentTabByTag("tab_more");
break ;
}
}
}
tab.xml
<? xml version = "1.0" encoding = "UTF-8" ?>
< TabHost android:id = "@+id/my_tabhost" android:layout_width = "fill_parent"
android:layout_height = "fill_parent" xmlns:android = "http://schemas.android.com/apk/res/android" >
< LinearLayout android:orientation = "vertical"
android:layout_width = "fill_parent" android:layout_height = "fill_parent" >
< FrameLayout android:id = "@android:id/tabcontent"
android:layout_width = "fill_parent" android:layout_height = "0.0dip"
android:layout_weight = "1.0" />
< TabWidget android:id = "@android:id/tabs" android:visibility="gone"
android:layout_width = "fill_parent" android:layout_height = "wrap_content"
android:layout_weight = "0.0" />
<RadioGroup android:id="@+id/tab_radiogroup"
android:background="@drawable/tabs_bg" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:gravity="center_vertical"
android:layout_gravity="bottom" android:orientation="horizontal" >
< RadioButton android:id = "@+id/radio_button_study"
android:layout_marginTop = "2.0dip" android:text = " 学习进度 "
android:drawableTop = "@drawable/account01" style = "@style/tab_button_bottom"
android:checked = "true" />
< RadioButton android:id = "@+id/radio_button_score"
android:layout_marginTop = "2.0dip" android:text = " 考试成绩 "
android:drawableTop = "@drawable/account02" style = "@style/tab_button_bottom" />
< RadioButton android:id = "@+id/radio_button_certificate"
android:layout_marginTop = "2.0dip" android:text = " 证书发放 "
android:drawableTop = "@drawable/account03" style = "@style/tab_button_bottom" />
< RadioButton android:id = "@+id/radio_button_fee"
android:layout_marginTop = "2.0dip" android:text = " 费用缴纳 "
android:drawableTop = "@drawable/account04" style = "@style/tab_button_bottom" />
< RadioButton android:id = "@+id/radio_button_more"
android:layout_marginTop = "2.0dip" android:text = " 更多 "
android:drawableTop = "@drawable/account05" style = "@style/tab_button_bottom" />
</ RadioGroup >
</ LinearLayout >
</ TabHost >
radio_button的背景XML图
<?xml version="1.0" encoding="UTF-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/tabbar_home_f" />
<item android:state_enabled="true" android:drawable="@drawable/tabbar_home" />
</selector>
styles.xml
<? xml version = "1.0" encoding = "utf-8" ?>
< resources >
<!-- TabHost 标签按钮样式 -->
< style name = "tab_button_bottom" >
< item name = "android:textSize" > 12px </ item >
< item name = "android:textColor" > #ffffffff </ item >
< item name = "android:ellipsize" > marquee </ item >
< item name = "android:gravity" > center_horizontal </ item >
< item name = "android:background" > @drawable /tab_btn_bg </ item >
< item name = "android:layout_marginTop" > 2.0dip </ item >
< item name = "android:button" > @null </ item >
< item name = "android:paddingTop" > 6dip </ item >
< item name = "android:drawablePadding" > 4dip </ item >
< item name = "android:layout_width" > fill_parent </ item >
< item name = "android:layout_height" > wrap_content </ item >
< item name = "android:layout_weight" > 1.0 </ item >
< item name = "android:singleLine" > true </ item >
</ style >
<!-- 页面标题 LinearLayout 样式 -->
< style name = "activity_title_background" >
< item name = "android:background" > @drawable /title_background </ item >
< item name = "android:layout_width" > fill_parent </ item >
< item name = "android:layout_height" > wrap_content </ item >
< item name = "android:layout_alignParentTop" > true </ item >
< item name = "android:gravity" > center </ item >
</ style >
<!-- 界面标题 TextView 样式 -->
< style name = "activity_title_text" >
< item name = "android:textSize" > 14dip </ item >
< item name = "android:textColor" > @drawable /white </ item >
< item name = "android:layout_width" > wrap_content </ item >
< item name = "android:layout_height" > wrap_content </ item >
< item name = "android:gravity" > center </ item >
</ style >
</ resources >
运行结果如下图所示
程序重要部分:
1. 红色字体部分。
2. 布局文件 tab.xml, 可以看到该布局文件中将 TabWidget 隐藏 ( android:visibility="gone" ) 而以一个 RadioGroup 取而代之。
3. 为 RadioGroup 设置 OnCheckedChangeListener 监听,通过 onCheckedChanged 方法对各个 RadioButton 点击事件的处理完成标签切换。
其实我当初考虑过为什么要用 RadioButton 而不用普通的 Button 。后来通过自己做项目,发现使用 RadioGroup 有以下优点:
1. 另外就是布局上比较方便易懂,不用再去用 LinearLayout 等布局去包含 Button 。
2. 我们可以很方便的获得当前选中的标签,当然通过 TabHost 的 tabHost.getCurrentTabTag() 和 getCurrentTab() 也是可以的。
3. 设置监听很方便,只需要为 RadioGroup 设置监听就行了,程序中对应的代码是
((RadioGroup) findViewById(R.id.tab_radiogroup ))
.setOnCheckedChangeListener(this );
如果用 Button 的话我们需要为所有的 Button 一个一个去设置监听,相对来说比较麻烦。
4. 或许最重要的一点是因为 RadioButton 本身就支持图片和文字的上下布局,只需指定图片和文字是什么就可以了而不需要我们自己去实现这种布局。
< RadioButton android:id = "@+id/radio_button_more"
android:layout_marginTop = "2.0dip"
android:text=" 更多 "
android:drawableTop="@drawable/account05"
style = "@style/tab_button_bottom" />