Android Tips #38 FragmentTabHost を使って Fragment をタブで切り替える

catch

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

FragmentTabHost とは

FragmentTabHost は Fragment をタブで切り替えるための View です。Android 1.6 から使用することができます。Activity にタブを表示して View を切り替える実装は以前は TabActivity を使っていましたが、現在は非推奨になっています。この機会に最新の実装方法を覚えておきましょう!

tab_host01

FragmentTabHost の使いかた

1. レイアウトを作る

まずはレイアウトを作ります。

<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/content"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"/>

    </LinearLayout>

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

まず大原則として大枠は FragmentTabHost にします。その中にタブの View である TabWidget @android:id/tabs という id で配置します。TabWidget は TabActivity のときにも使われていた View なので馴染み深いと思います。また FrameLayout を @android:id/tabcontent という id で配置します。これは実際には表示されない View になりますが、こうすることで FragmentTabHost がそれぞれの View をパーツとして使ってくれます。最後に Fragment を追加するレイアウトに好きな id を入れて完了です。今回は content という名前にしました。

2. FragmentTabHost をセットアップする

次に Activity の実装です。Fragment を取り扱うので FragmentActivity を継承します。onCreate() で FragmentTabHost を findViewById() で参照し FragmentTabHost#setup() メソッドを呼びます。引数には Context と FragmentManager を渡さなければいけないので FragmentActivity#getSupportFragmentManager() で取得した FragmentManager を渡すようにします。

FragmentTabHost host = (FragmentTabHost)findViewById(android.R.id.tabhost);
host.setup(this, getSupportFragmentManager(), R.id.content);

3. TabSpec を追加する

あとはタブの情報である TabSpec で作っていきます。TabSpec のインスタンスは FragmentTabHost#newTabSpec() で生成します。引数には TabSpec のタグを渡します。 必ず設定しておかなければいけないのが TabSpec#setIndicator() です。これはタブの View になります。String を渡すとデフォルトのタブボタンの View が使われます。
最後に FragmentTabHost#addTab() でタブを追加します。第一引数に TabSpec を、第二引数にタブが選択されたときに表示したい Fragment を Class で渡します。第三引数には Fragment で読み込みたいデータを Bundle で渡します。特に必要ない場合は null でOKです。

TabSpec tabSpec1 = host.newTabSpec("tab1").setIndicator("Tab1");
host.addTab(tabSpec1, SampleFragment.class, null);

以下が Activity の全ソースです。Fragment は適当に。

MainActivity.java

package jp.classmethod.android.sample.fragmenttabhost;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TabHost.TabSpec;
import android.widget.TextView;

public class MainActivity extends FragmentActivity {

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

        setContentView(R.layout.activity_main);
        FragmentTabHost host = (FragmentTabHost) findViewById(android.R.id.tabhost);
        host.setup(this, getSupportFragmentManager(), R.id.content);

        TabSpec tabSpec1 = host.newTabSpec("tab1");
        Button button1 = new Button(this);
        button1.setBackgroundResource(R.drawable.tab_left);
        tabSpec1.setIndicator(button1);
        Bundle bundle1 = new Bundle();
        bundle1.putString("name", "Tab1");
        host.addTab(tabSpec1, SampleFragment.class, bundle1);
        
        TabSpec tabSpec2 = host.newTabSpec("tab2");
        Button button2 = new Button(this);
        button2.setBackgroundResource(R.drawable.tab_center);
        tabSpec2.setIndicator(button2);
        Bundle bundle2 = new Bundle();
        bundle2.putString("name", "Tab2");
        host.addTab(tabSpec2, SampleFragment.class, bundle2);
        
        TabSpec tabSpec3 = host.newTabSpec("tab3");
        Button button3 = new Button(this);
        button3.setBackgroundResource(R.drawable.tab_right);
        tabSpec3.setIndicator(button3);
        Bundle bundle3 = new Bundle();
        bundle3.putString("name", "Tab3");
        host.addTab(tabSpec3, SampleFragment.class, bundle3);
    }
    
    public static class SampleFragment extends Fragment {
        
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            
            TextView textView = new TextView(getActivity());
            textView.setGravity(Gravity.CENTER);
            textView.setText(getArguments().getString("name"));
            
            return textView;
        }
        
    }
}

tab_host01

tab_host02

tab_host03

まとめ

タブの切り替えはよく使われる UI のひとつだと思いますが Fragment を使うととても管理しやすいです。何より以前良く使われていた TabActivity の実装方法は非推奨になっているので、これからは FragmentTabHost を使うようにしていきましょう。
しかし Support Package で導入されてから Fragment を使う機会がかなり増えてきましたね。Android 開発者にとって Fragment を使いこなすことは必須といえますね!今回は初歩的な解説となりましたが、これからも Fragment を使った実装 Tips をシェアしていきますのでよろしくお願いします!

参考