2012年1月11日水曜日

Support Packageを使ってFragmentを利用する

先日、私が公開している「サポセン前の問診票」アプリケーションにFragmentを適用した
形に作り替えたので、その時に発生した現象と、Framgentの使い方をメモしておきます。

前提:
※Support Package v4を利用する。

以下が大体の手順です。

  1. レイアウトXMLにFragmentを含むレイアウトを定義する。
  2. FragmentActivityを継承したActivityのクラスを作成する。
  3. 普通に起動。


だけです。終わり。というと内容が薄いので、

レイアウトは以下のような感じになります。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <FrameLayout
        android:id="@+id/framelayoutmain"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
     <fragment
         android:id="@+id/fragment1"
         android:name="com.sample.ui.MainFragment"
         android:layout_width="fill_parent" android:layout_height="fill_parent" />

    </FrameLayout>
</LinearLayout>

Activityのソースコードはこれまで通りとなります。

public class MainActivity extends FragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

Activityが実行された時点でFragmentも呼び出されて表示されますので、
Fragment外で処理する事が無ければ、Activity側では何も記述しなくても良いです。
ポイントとしてはFragmentActivityを継承しないと実行時にエラーになってしまいます。

あとは、Fragmentのプログラムの方で処理するプログラムを
実装すれば良いです。

次に、FragmentをBackStackに積む方法は以下のコードです。

SubFragment fragment = new SubFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.framelayoutmain, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(null);
ft.commit();

FragmentTransactionクラスがFragmentのBackStackの状態を管理しているようです。
ft.replaceでレイアウトに配置されているFragmentを置き換えます。
これは、Fragmentが複数配置されている場合でも、それぞれのFragmentが配置されているViewを指定して置き換える事ができます。
setTransitionは置き換え時のアニメーションを指定します。
addToBackStackは置き換え後の状態(アクティビティ全体)をBackStackに積みます。
最後にcommitを実行して確定します。

注意点として、ft.replaceした場合、下にあるFragmentの内容が見えてしまいます。
(背景が透明になる)
したがって、背景を画像や色を指定して、下のFragmentが見えないようにしないと
いけません。(これはSupport Packageのみの現象?)
しかも、ListFragmentを利用した時(他のFragmentでも?)、画面をタッチすると、下に配置されたFragmentもタッチを検出しますので、処理が実行されてしまいます。
BackStackに積む前に下のFragmentの処理が実行されないようにEnabled = falseにするか、
getFragmentManager().getBackStackEntryCount()をチェックして、積まれていたら
処理をスキップするなど工夫をしないといけないようです。

Google+に書き残したコメントです。

https://plus.google.com/u/0/114183076079015753160/posts/cyodhHmgRy9
https://plus.google.com/u/0/114183076079015753160/posts/3kDyzNe1mej
https://plus.google.com/u/0/114183076079015753160/posts/UHcTUgp7Hky