Android TabHost多标签页几乎是所有APP中必备的控件,如通迅录的【拨号、通话记录、联系人】,微信的【聊天、联系人、发现】,如下图
Android API13之后官方就不推荐使用TabActivity了,取而代之的是FragmentActivity+FragmentTabHost+Fragment的组合
大致用法
要显示多标签页的Activity继承FragmentActivity,里面定义一个FragmentTabHost类型的对象,
另外定义几个类继承Fragment,实现每个Tab的具体功能并加载对应界面布局
然后用FragmentTabHost的addTab方法将Fragment添加到FragmentTabHost中显示,可以点击切换多个Fragmen(即每个标签页)
最后再为MainActivity添加滑动手势来切换标签页
写了个Demo,
MainActivity的主要代码:
public class MainActivity extends FragmentActivity{
private FragmentTabHost mTabHost;
private LayoutInflater layoutInflater;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layoutInflater=LayoutInflater.from(this);
mTabHost=(FragmentTabHost)findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(),R.id.realtabcontent);
mTabHost.addTab(mTabHost.newTabSpec("首页").setIndicator("首页"),FragmentPage1.class,null);
mTabHost.addTab(mTabHost.newTabSpec("聊天").setIndicator("聊天"),FragmentPage2.class,null);
mTabHost.addTab(mTabHost.newTabSpec("发现").setIndicator("发现"),FragmentPage3.class,null);
mTabHost.addTab(mTabHost.newTabSpec("其他").setIndicator("其他"),FragmentPage4.class,null);
}
}
首先获取tabhost,然后setup
注意mTabHost和setup()参数的id为安卓自带ID,这一点在写布局文件时也要注意
setIndicator指定标签页的显示label,可以用字符串也可以用自定义的View显示
对应的布局文件为activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="${packageName}.${activityClass}" >
<FrameLayout
android:id="@+id/realtabcontent"
android:layout_width="match_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">
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dip"
android:layout_weight="0"/>
</android.support.v4.app.FragmentTabHost>
</LinearLayout>
FragMentPage1.Java的源码
public class FragmentPage1 extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_page1, null);
}
}
因为标签页中没有多余功能,所以代码只加载布局显示就好
布局文件为fragment_page1.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="page1"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
FragmentPage2、3、4与FragmentPage1一致,此处不再给出
这样四个标签页就生成了
最后为Tab添加滑动切换的功能
- MainActivity实现OnGestureListener接口,
- 定义一个GestureDetector对象来处理手势事件
- 并重载onFling方法处理滑动事件,计算两次getX()的位置来判断滑动方向
- 注意,onTouchEvent方法也要重载,不然没法获取触摸事件滑动事件自然也就无效了
修改后的MainActivity源码:
public class MainActivity extends FragmentActivity implements OnGestureListener{
private GestureDetector mDetector;
private FragmentTabHost mTabHost;
private LayoutInflater layoutInflater;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layoutInflater=LayoutInflater.from(this);
mTabHost=(FragmentTabHost)findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(),R.id.realtabcontent);
mTabHost.addTab(mTabHost.newTabSpec("首页").setIndicator("首页"),FragmentPage1.class,null);
mTabHost.addTab(mTabHost.newTabSpec("聊天").setIndicator("聊天"),FragmentPage2.class,null);
mTabHost.addTab(mTabHost.newTabSpec("发现").setIndicator("发现"),FragmentPage2.class,null);
mTabHost.addTab(mTabHost.newTabSpec("其他").setIndicator("其他"),FragmentPage2.class,null);
mDetector = new GestureDetector (this);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return this.mDetector.onTouchEvent(event);
}
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// TODO Auto-generated method stub
int currentTab=this.mTabHost.getCurrentTab();
if(currentTab<3 && e1.getX()-e2.getX()>120){
Log.i("MyLog", currentTab+"");
this.mTabHost.setCurrentTab(currentTab+1);
}
else if(currentTab>0 && e1.getX()-e2.getX()<-120){
Log.i("MyLog", currentTab+"");
this.mTabHost.setCurrentTab(currentTab-1);
}
return true;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
}