1. 写在前面

出于对新事物的好奇, 接触了一下Android, 主要是看书(《Anroid应用开发深入学习实录》 关立勋)、Google和看文档。使用的android-sdk的platform最低是android-14, 然后有android-17,android-20以及android-L(电脑配置暂时比较低,没法把每个版本都测试一遍)
此时此刻Intellij IDEA社区版还没法渲染出android-20和android-L,所以我基本都是用的android-17
虽然书的出版日期比较新, 但其中有些内容还是已经过时了

2. TabHost的使用详解

2.1 项目结构

先新建一个项目,使用以前构建项目的方法(虽然现在有了Gradle, 但是对于初学者来说学习成本稍高, 暂时搁置):
MySetting.java在这里没用,忽略它……

project structure

2.2 App布局

布局main.xml:

<?xml version="1.0" encoding="utf-8"?>
<TabHost
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tabHost">
  <LinearLayout
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:orientation="vertical">
    <TabWidget
        android:id="@android:id/tabs"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
    </TabWidget>
    <FrameLayout
        android:id="@android:id/tabcontent"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
      <TextView
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:text="@string/textview1"
          android:id="@+id/textView1" android:layout_gravity="left|top"/>
      <TextView
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:text="@string/textview2"
          android:id="@+id/textView2" android:layout_gravity="center_horizontal|top"/>
      <TextView
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:text="@string/textview3"
          android:id="@+id/textView3" android:layout_gravity="right|top"/>
    </FrameLayout>
  </LinearLayout>
</TabHost>

strings.xml不放了, 随便什么字符串无所谓

2.3 逻辑代码

想要实现的就是添加三个Tab标签, 改变Tab标签的时候会弹出一个对话框, 按照书上及网上搜到的大部分代码, MyActivity.java应该是:

public class MyActivity extends Activity {
    @Override
    public void onCreate( Bundle savedInstanceState ) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mTabHost = getTabHost();
        mTabHost.addTab...
    }
}

这样的话有个问题: 查文档发现TabActivity在API Level 13中已经被弃用了。有:
This class was deprecated in API level 13. New applications should use Fragments instead of this class; to continue to run on older devices, you can use the v4 support library which provides a version of theFragment API that is compatible down to DONUT.
还有一句:
A replacement for TabActivity can also be implemented by directly using TabHost.
这其实意味着如果我们不考虑向下兼容的问题, 其实可以直接将上述代码写成:

package com.hecate.Apollo;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.TabHost;

public class MyActivity extends Activity {
    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TabHost mTabHost = (TabHost) findViewById(R.id.tabHost);
        mTabHost.setup();
        mTabHost.addTab( mTabHost.newTabSpec("first").setIndicator("Tab 1",getResources().getDrawable(R.drawable.img1)).setContent(R.id.textView1) );
        mTabHost.addTab( mTabHost.newTabSpec("second").setIndicator("Tab 2",getResources().getDrawable(R.drawable.img2)).setContent(R.id.textView2) );
        mTabHost.addTab( mTabHost.newTabSpec("third").setIndicator("Tab 3",getResources().getDrawable(R.drawable.img3)).setContent(R.id.textView3) );

        mTabHost.setBackgroundColor(Color.parseColor("blue"));
        mTabHost.setBackgroundResource(R.drawable.background);
        mTabHost.setCurrentTab(0);

        mTabHost.setOnTabChangedListener( new TabHost.OnTabChangeListener() {
            @Override
            public void onTabChanged( String tabId ) {
                Dialog dialog = new AlertDialog.Builder( MyActivity.this )
                        .setTitle("Change Tabs")
                        .setMessage("You chosen "+tabId+" Tab")
                        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                            public void onClick( DialogInterface dialogInterface, int whichButton ) {
                                dialogInterface.cancel();
                            }
                        }).create();
                dialog.show();
            }
        });

    }
}

也就是直接继承Activity, 然后不使用getTabHost()方法而是findViewById(), 这时候又有一个注意点, 在TabHost文档的setup()方法中有:
Call setup() before adding tabs if loading TabHost using findViewById().
就是说如果你不是用getTabHost而是findViewById获取的TabHost,那在使用addTab()方法前要使用setup()方法。

2.4 运行测试

按照以上完成之后, 再添加相应的资源文件就可以成功运行了(在API Level 13以上):
tabhost_layout
原谅我的背景图片、、、点击TAB2后弹窗:
tabhost_popup

2.5 向下兼容

说完了不向下兼容的方法, 那如果需要向下兼容呢? 正如一开始的文档所说, 使用Fragments和android.support.v4 library即可, 具体可以去查看详细的文档, 里面给了一个示例, 我把示例代码贴出来, 就不分析了:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.app.FragmentTabHost
    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:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TabWidget
            android:id="@android:id/tabs"
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="0"/>

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_weight="0"/>

        <FrameLayout
            android:id="@+id/realtabcontent"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"/>

    </LinearLayout>
</android.support.v4.app.FragmentTabHost>

Java代码:

import com.example.android.supportv4.R;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;

/**
 * This demonstrates how you can implement switching between the tabs of a
 * TabHost through fragments, using FragmentTabHost.
 */
public class FragmentTabs extends FragmentActivity {
    private FragmentTabHost mTabHost;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.fragment_tabs);
        mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
        mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);

        mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
                FragmentStackSupport.CountingFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
                LoaderCursorSupport.CursorLoaderListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
                LoaderCustomSupport.AppListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
                LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);
    }
}