2012年10月26日金曜日

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を仕込む。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
    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()等)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    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

1
2
3
<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
→無し

 

1
2
3
4
5
6
7
8
9
10
11
12
13
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の可能性がまた一つ広がるのではないでしょうか。

0 件のコメント:

コメントを投稿