「PreferenceFragmentを使って2Paneな設定画面を作成する」「Fragmentを使ってMenuを動的に作成する」にて、Android3.0で追加された、Fragmentについて紹介してきました。
今回も、Fragmentの機能を紹介していきます。
FragmentはActivityなどと同じ様に、ライフサイクルを持ちます。
それらを確認した上で、Button操作による、Fragmentの追加/編集を行っていきましょう。
Fragmentのライフサイクル
Fragmentにはライフサイクルがあります。
それは以下の通り。基本的な流れはActivityと同様ですが、UIの生成等に関わるMethodが追加されています。
〜コアライフサイクルMethod〜
1. onAttach(Activity)
→Activityに関連付けされた際に一度だけ呼ばれる。
2. onCreate(Bundle)
→Fragmentの初期化処理を行う。
3. onCreateView(LayoutInflater, ViewGroup, Bundle)
→Fragmentに関連付けるViewを作成し、returnする。
4. onActivityCreated(Bundle)
→親となるActivityの「onCreate」の終了を知らせる。
5. onStart()
→Activityの「onStart」に基づき開始される。
6. onResume()
→Activityの「onResume」に基づき開始される。
〜終了/復帰処理にあたるMethod〜
1. onPause()
→Activityが「onPause」になったり、Fragmentが変更更新され、
操作を受け付けなくなった場合に呼び出される。
2. onStop()
→フォアグラウンドで無くなった場合に呼び出される。
3. onDestroyView()
→Fragmentの内部のViewリソースの整理を行う。
4. onDestroy()
→Fragmentが殺される最後に呼び出される。
5. onDetach()
→Activityの関連付けから外された時に呼び出される。
以上のMethodを踏まえ、全てOverrideし、Logを仕込む。
public static class UpFragment extends Fragment implements OnClickListener { public static String TAG = "FragmentLifeCycle"; @Override public void onAttach(Activity act){ super.onAttach(act); Log.d(TAG,"Fragment-onAttach"); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG,"Fragment-onCreate"); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d(TAG,"Fragment-onCreateView"); View v = inflater.inflate(R.layout.component_button,container,false); return v; } @Override public void onActivityCreated(Bundle bundle){ super.onActivityCreated(bundle); Log.d(TAG,"Fragment-onActivityCreated"); } @Override public void onStart(){ super.onStart(); Log.d(TAG,"Fragment-onStart"); } @Override public void onResume(){ super.onResume(); Log.d(TAG,"Fragment-onResume"); } @Override public void onPause(){ super.onPause(); Log.d(TAG,"Fragment-onPause"); } @Override public void onStop(){ super.onStop(); Log.d(TAG,"Fragment-onStop"); } @Override public void onDestroyView(){ super.onDestroyView(); Log.d(TAG,"Fragment-onDestroyView"); } @Override public void onDestroy(){ super.onDestroy(); Log.d(TAG,"Fragment-onDestroy"); } @Override public void onDetach(){ super.onDetach(); Log.d(TAG,"Fragment-onDetach"); } }
Fragmentの追加/編集
まず、Fragmentを使用する場合は、 Fragment class を継承したクラスを用意します。
今回用意したのは、上記 Log 出力を入れ込んだ物(小変更 UpFragment)と、TextViewを表示する、
DownFragmentを作成しました。
Fragment内部にTextViewを持つため、それを「onCreateView」において呼び出しています。
「findViewById」を常日頃「onCreate」で呼び出している様なイメージでしょうか。
呼び出すViewの内容は、続けて引用する component_text.xml で定義しています。
LayoutInflater#inflateは、「リストビューをカスタマイズする」でも使用しています。
Fragment内部に持つ、コンポーネントにアクセスする場合のポイントは以下になります。
1.LayoutInflater#inflateにて、Layoutファイルを指定
2.指定したLayoutファイルから、findViewByIdでコンポーネントを指定
3.それぞれのコンポーネントに対する処理(TextView#setText()等)
public static class DownFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.component_text,container,false); return v; } } public static class UpFragment extends Fragment implements OnClickListener { int cnt; UpFragment(int counter){ cnt = counter; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.component_button,container,false); View bt = v.findViewById(R.id.button1); ((Button)bt).setOnClickListener(this); ((Button)bt).setText("Load the TextView-Fragment"+cnt); return v; } }
component_text.xml
<TextView android:text="This is a Textview.." android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" xmlns:android="http://schemas.android.com/apk/res/android"></TextView>
次に、Fragmentの登録部分を作成していきます。
基本的な流れは「Fragmentを使ってMenuを動的に作成する」で紹介した流れと同じです。
まずFragmentTransactionをFragmentManagerから取得します。
次に、Flagmentを登録(replace)します。
replaceは、既に「R.id.fragment01」のViewIdで追加指定(add等)しているFragment要素を破棄(remove)
することと同様の操作になります。
アニメーションの指定には、以下を指定します。
#和演算を行うことで、同時に指定できます。
- TRANSIT_FRAGMENT_OPEN
→開く時のアニメーションを行うよう指定
- TRANSIT_FRAGMENT_CLOSE
→閉じる時のアニメーションを行うよう指定
- TRANSIT_NONE
→無し
void addFragmentToStack() { // フラグメントのインスタンスを生成する。 Fragment newFragment = new UpFragment(counter++); // ActivityにFragmentを登録する。 FragmentTransaction ft = getFragmentManager().beginTransaction(); // Layout位置先の指定 ft.replace(R.id.fragment01, newFragment); // Fragmentの変化時のアニメーションを指定 ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); ft.addToBackStack(null); ft.commit(); }
この処理を、Button押下時に呼び出す様に作成します。
#処理自体は割愛します。
最後に、実行結果のキャプチャを添付します。
実行時の画面は以下左図の通りです。
「Load the TextView-Fragment0」を押下すると、真ん中の図の様にTextViewが挿入されます。
0番目のFragmentから呼び出されたので、末尾に0が付加されています。
「Button」を押下すると、「Load the TextView-Fragment0」の末尾の数値がカウントアップします。
これは、Fragmentがスタック状に重なっている様子を示しています。(右図)
同様に、「Load the TextView-Fragment1」を押下すると、以下左図の様に、
TextViewの末尾の数値が増加します。これも同様にスタック状に重なっている事を示しています。
この先も繰り返しで、数値を変化させていけます。
本サンプルで面白いのは、BACKボタンを押下した時の動作です。
従来のACTIVITYであれば、BACKボタンを押下した場合、画面ごと切り替わってしまいますが、
本サンプルでは、Fragmentが一枚戻る形、すなわち、図が一つ戻る様に動作します。
Fragmentを用いることで、UIの可能性がまた一つ広がるのではないでしょうか。
#2011/03/19 追記