Help us understand the problem. What is going on with this article?

Fragmentを用いたActionBarによるTab表示

More than 5 years have passed since last update.

タブ表示を用いたレイアウトの使い方を学んだのでφ(..)メモメモ

環境

OS X 10.9.3
Android Studio (Beta) 0.8.0
Sony SOL25 Android 4.4.2(API 19)

build.gradle(app)
apply plugin: 'com.android.application'

android {
    compileSdkVersion 19
    buildToolsVersion "20.0.0"

    defaultConfig {
        applicationId "test.mackiso.tabtest"
        minSdkVersion 14
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

1. Project作成

まずはこちらを参考にHello, worldのアプリの状態からスタート。
MainActivityは以下のようになっております。

MainActivity.java
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

ちなみに、レイアウトファイルはダミーでいいので以下のように。

activity_main.xml
<RelativeLayout
    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:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".activity.MainActivity">

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</RelativeLayout>

2. Fragment作成

次に各タブを選択した際に表示させるFragmentを作成します。
対象はAndroid4.0以上としているのでandroid.support.v4.app.Fragmentは使わずandroid.app.Fragmentを使用しました。

Fragmentは以下のように。

FirstTabFragment.java
import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import test.mackiso.tabtest.R;


public class FirstTabFragment extends Fragment {

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_first_tab, container, false);
    }

}

レイアウトファイルは以下のようにしました。

fragment_first_tab.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"
    tools:context=".fragment.FirstTabFragment">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="This is first fragment." />

</LinearLayout>

ここで、TextViewの表示テキストを
android:text="@string/first_fragment"
のようにstrings.xmlから参照しようとするとエラーが出てしまいました。
原因は不明です、誰か助けてください。(他力本願)

タブを切り替えて表示するので、同様にしてFragmentをあと2つ作成しました。
コードは割愛。FirstがSeond,Thirdとなっただけです。

3. リスナーの実装

タブを変更した時のリスナーを作成します。
ActionBar.TabListenerインターフェースを実装したクラスの定義です。

  • onTabReselected(ActionBar.Tab tab, FragmentTransaction ft)
  • onTabSelected(ActionBar.Tab tab, FragmentTransaction ft)
  • onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft)

この3つを実装していく感じですね。
リスナーは以下のようにしました。

TabListener.java
import android.app.ActionBar;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;

import test.mackiso.tabtest.R;

public class TabListener<T extends Fragment> implements ActionBar.TabListener {
    private Fragment mFragment;
    private final Activity mActivity;
    private final String mTag;
    private final Class<T> mClass;

    //コンストラクタ
    public TabListener(Activity activity, String tag, Class<T> clz) {
        mActivity = activity;
        mTag = tag;
        mClass = clz;
        mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag);
    }

    //タブが選択されたとき
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {

        if (mFragment == null) {
            mFragment = Fragment.instantiate(mActivity, mClass.getName());
            FragmentManager fm = mActivity.getFragmentManager();
            fm.beginTransaction().add(R.id.container, mFragment, mTag).commit();
        } else {
            if (mFragment.isDetached()) {
                FragmentManager fm = mActivity.getFragmentManager();
                fm.beginTransaction().attach(mFragment).commit();
            }

        }
    }

    //タブの選択が解除されたとき
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
        if (mFragment != null) {
            FragmentManager fm = mActivity.getFragmentManager();
            fm.beginTransaction().detach(mFragment).commit();
        }
    }

    //選択されたタブが選択されたとき
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
    }
}

4. ActionBarのモードを変更

せっかく定義したタブですが、MainActivityに設定されていません。
MainActivityのActionBarをgetしてModeをSetです。English。
ちなみにSetできるModeには以下のものがあるとか。

  • NAVIGATION_MODE_TABS
  • NAVIGATION_MODE_LIST
  • NAVIGATION_MODE_STANDARD

ふむ、まあ、置いとこう。
TABモードに設定して作ったタブをSetしましょ。
以下のようにMainActivityのを変更です。

MainActivity.java(onCreateメソッド)
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //ActionBarをGetしてTabModeをセット
        final ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        actionBar.addTab(actionBar.newTab()
                .setText("First")
                .setTabListener(new TabListener<FirstTabFragment>(
                        this, "tag1", FirstTabFragment.class)));
        actionBar.addTab(actionBar.newTab()
                .setText("Second")
                .setTabListener(new TabListener<SecondTabFragment>(
                        this, "tag2", SecondTabFragment.class)));
        actionBar.addTab(actionBar.newTab()
                .setText("Third")
                .setTabListener(new TabListener<ThirdTabFragment>(
                        this, "tag3", ThirdTabFragment.class)));
    }

5. 実行確認

私の実機(Sony SOL25)で動作を確認しました。
Screenshot_2014-07-13-03-00-43.png

参考

Android ActionBarとFragmentを使用してTab画面を表示する(Android 4.0以上)

アクションバーのタブ・ナビゲーション

Develop Apps | Android Developers

おわりに

GithubにてProjectを公開しております。
また、ご指摘やアドバイス等を頂けると幸いです。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away