Android Tips #28 Android 1.6 から Fragment を使う

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

はじめに

Fragment は Android 3.0 (APIレベル11) から導入されたコンポーネントです。Fragment は Support Package でサポートされているので Android 1.6 (APIレベル4) から使用することができます。ということで今回は Android 1.6 〜 2.3 くらいまでをターゲットに開発してきた方々を対象に、 Fragment についての概要、そして Support Package を使って Fragment を使うにはどうすればよいか解説したいと思います!

Fragment とは?

Activity を機能・振る舞いごとに分割できる!

Fragment は Activity を 機能・振る舞いごとに分割するための UI モジュールです。Fragment を用いることで Activity の UI を簡単に分割して構成することができます。動的な追加や削除が容易にでき、また複数の画面に同じ Fragment を配置できたりします。ライフサイクルを持っているので、小さな Activity と捉えても良いかも知れません。

こういったときに便利です!

画面を構成する部位ごとを Fragment としてモジュール化すれば、画面サイズに応じたレイアウトがしやすくなります。例えば下図のように「タブレットでは一画面、スマホ (Handset) では二画面にする」というレイアウトにしたい場合、レイアウトを Fragment に分割してあげればレイアウトをゴリゴリいじる必要もなく実装できますし、またさらに他の画面に使い回すこともできます。多画面に対応するアプリを作りたい場合 Fragment はもはや必須!ですね!

frag01

Fragment を Activity で使う

ということで Support Package の Fragment クラスを使ってみたいと思います。

レイアウトXMLで追加する

1. カスタム Fragment を作成する

まずは Fragment のレイアウトを 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"
    android:gravity="center"
    android:background="#eeeeee"
    >
    
    <TextView 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:text="Hello, SupportFragment!"
        />
    
    <ImageView 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher"
        />

</LinearLayout>

次に Fragment クラスを自作します。親クラスは android.support.v4.app.Fragment を使います。android.app.Fragment ではないので注意しましょう!

frag02

onCreateView() メソッドをオーバーライドし、渡される LayoutInflator クラスを使って先ほどのレイアウトを View にします。

package jp.classmethod.android.sample.supportpackage.fragment;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MainFragment extends Fragment {
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_main, container, false);
    }

}

これで Fragment ができました!

2. FragmentActivity を継承した Activity を作る

次に作成した Fragment を Activity に追加します。レイアウトXML で fragment タグを使ってレイアウトに追加します。class 要素に 先ほど作成した Fragment のクラス名を入れます。

<fragment 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    class="jp.classmethod.android.sample.supportpackage.fragment.MainFragment" />

次に Activity クラスを作ります。Fragment を取り扱う Activity クラスは FragmentActivity を継承しなければなりません。あとは普通に setContentView() して終わりです。

package jp.classmethod.android.sample.supportpackage.fragment;

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

public class MainActivity extends FragmentActivity {

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

}

無事に Android 1.6 で Fragment が表示できました!

frag03

FragmentManager で動的に追加する

FragmentManager クラスを使うと、 Fragment を Java から動的に追加することができます!

1. Fragment を作る

レイアウトXMLで追加したときと同様、まずは Fragment を作ります。

2. FragmentActivity を継承した Activity を作る

ここも先ほどと同様に FragmentActivity を継承した Activity を作ります。今回は動的に追加したいので、レイアウトXMLに fragment タグは書きません。以下のように Fragment を追加する View (LinearLayout) を配置しておきます。

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/layout_a"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" 
        android:orientation="vertical"
        android:background="#ff0000"
        />

    <LinearLayout
        android:id="@+id/layout_b"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical"
        android:background="#00ff00"
         />

</LinearLayout>

3. FragmentManager と FragmentTransaction を呼び出す

次に onCreate() で Fragment を管理する FragmentManager クラスを呼び出します。FragmentActivity#getSupportFragmentManager() で呼び出します。このとき android.support.v4.app.FragmentManager クラスを使うようにしないと Android 1.6 では動作しないので注意が必要です。

frag04

FragmentManager manager = getSupportFragmentManager();

次に FragmentManager#beginTransaction() で FragmentTransaction クラスを呼び出します。FragmentTransaction は Fragment の追加や削除などを1つの処理としてまとめるためのトランザクションクラスです。

FragmentTransaction tx = manager.beginTransaction();

4. Fragment をスタックに追加する

FragmentTransaction#add() を使って Fragment を追加します。追加先の View の ID を指定すると、その対象の View に Fragment が追加されます。また Fragment にはタグを付けることができます。add() したときに既にバックスタックに同じタグの Fragment が存在する場合、Fragment は新規作成されず、既にインスタンス化してある Fragment が再表示されます。最後に commit() すると操作内容が反映されます。

tx.add(R.id.layout_a, new MainFragment(), "fragment_a");
tx.add(R.id.layout_b, new MainFragment(), "fragment_b");
tx.commit();

実行すると、2つの LinearLayout にそれぞれ同じ Fragment が配置されます!

frag05

サンプルソース

サンプルソースを github で公開しました!ソース自体たいした量はありませんが、ぜひ参考にしてください♪

suwa-yuki/SupportFragmentSample

まとめ

Fragment は画面が複雑になればなるほど便利に働く気がします。最新 SDK バージョンでは Fragment の中に Fragment をネストできるようになったので、さらに機能的になってます(SupportPackageでもサポートされています!)。とっても便利なのでぜひ覚えて使いましょう!
サブクラスに DialogFragment ListFragment などもあるので、こちらは次回以降に解説したいと思います。

参考