2013年10月28日月曜日

Fragmentを使ってみる(動的に追加&引数を渡す)

前回の「Fragmentを使ってみる」に続き、Fragmentド━━━━m9(゚∀゚)━━━━ン!!
今回は動的にFragmentを追加してみたいと思います( ̄ー ̄)ニヤリ
(レイアウトXMLで定義したFragmentはreplaceなどで切り替えが行えないので、
動的にコードからaddなどを利用する必要がある。)

ついでに引数も渡してみたいと思います( ̄ー ̄)ニヤリ

Fragmentに引数を渡したい場合にはこちらの方法でも渡せます!こっちのが良いかもです!
Fragmentを使ってみる(ファクトリメソッドを利用して引数を渡す)

■AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.fragment2"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="8" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.fragment2.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
■fragment_main.xml
fragmentとは前回と同じレイアウトを利用します。
<?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:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        />
     
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher"
        />
 
</LinearLayout>

■activity_main.xml
メインのレイアウトでは、Fragmentの挿入先として、
LinearLayoutの「layout_fragment_1」、「layout_fragment_2」を用意しておきます。
<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_fragment_1"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical"
        android:background="#ff0000"
        />
 
    <LinearLayout
        android:id="@+id/layout_fragment_2"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical"
        android:background="#00ff00"
         />
 
</LinearLayout>

■MainFragment.java
メインのActivityで設定されたBundleからデータを取得して、
TextViewに設定を行います。

Fragmentはインスタンス生成時に引数を渡す事が出来ないそうです。
なぜかというと、Fragmentがメモリが足らなくなって破棄された場合などで、
再度Fragmentが構築される際に空のコンストラクタから
Fragmentのインスタンスを再生成するためらしいです。ガ━━(;゚Д゚)━━ン!!
※そのため空のコンストラクタが用意されていない場合には、上記の状態になるとアプリが落ちるそうです。

こういう事情もあり、Bundleを利用して引数を設定することで、
再生成のときに復元をしてくれるようになります。
package com.example.fragment2;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class MainFragment extends Fragment {

    /**
     * Viewの生成
     * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
     
        //Bundleで保存されたデータを復元
     String title = getArguments().getString("title");

     //
        Log.d("onCreateView", title);
        
     //第1引数:レイアウトXMLファイルのリソースID、
     //第2引数:
     //第3引数:trueにするかfalseにするかで戻り値となるルートビュー(View)が変わる。
     //       trueの場合には、第2引数で渡したViewGrou、falseの場合には第1引数で渡したリソースIDがルートビューになる
     View view = inflater.inflate(R.layout.fragment_main, container, false);
     //
        TextView text = (TextView)view.findViewById(R.id.text_view);
        text.setText(title);
     //
        return view;
    }

}
■MainActivity.java

メインActivityのソースコードになります。

動的にFragmentを追加するには、FragmentManagerを利用します。

こちらのサイトから抜粋させて頂きましたъ(゚Д゚)グッジョブ!!
Android Fragment を使う
FragmentManager でできることは次のようなことになります。
・findFragmentById() もしくは findFragmentByTag() で Activity に存在する Fragment を取得
・popBackStack() でバックスタックの Fragment を pop off (ユーザーが BACK ボタンを押したときと同じ動作)
・addOnBackStackChangedListener() を使って、バックスタックの変更用リスナーを登録
・FragmentTransaction を開く

Fragment Transactionについて
・各トランザクションは一度に行いたい変更の組み合わせ
・実行したいすべてのトランザクションを add(), remove(), replace() などを使ってセットし、それから commit() を呼び出してトランザクションを適用させる
・例えば、以前の状態をバックスタックに保存して、別のフラグメントに置き換えるにはこんな感じになる

Fragmentの引数について
BundleをFragmentのsetArgumentsに渡す事でFragmentに値を渡します。
その際の注意点として次の点があるそうです。
こちらのサイトから抜粋
【Android 実装の罠 #1】 Fragment#setArguments()
・setArguments()は、FragmentManagerによってAddされた以降は呼んではいけない
・setArguments()呼び出し時に、Fragment#mIndexの評価を行っている。0以上であればIllegalStateExceptionをスローする
・mIndexは、FragmentManager#makeActive()呼び出し時に入力される
package com.example.fragment2;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
 
public class MainActivity extends FragmentActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        //Fragmentを管理するFragmentManagerを取得
        FragmentManager manager = getSupportFragmentManager();
        //追加や削除などを1つの処理としてまとめるためのトランザクションクラスを取得
        FragmentTransaction tx = manager.beginTransaction();
        
        //1つ目のfragmentを生成
        MainFragment fragment1 = new MainFragment();
        Bundle bundle1 = new Bundle();
        bundle1.putString("title", "キタ――(゚∀゚)――!!");
        // フラグメントに渡す値をセット
        fragment1.setArguments(bundle1);

        //2つ目のfragmentを生成
        MainFragment fragment2 = new MainFragment();
        Bundle bundle2 = new Bundle();
        bundle2.putString("title", "クル━━━━(゚∀゚)━━━━!!");
        fragment2.setArguments(bundle2);
        
        //Fragment をスタックに追加する
        //メインレイアウトに対して追加先のビューのID、Fragment、Fragmentのタグ。
        //add() したときに既にバックスタックに同じタグの Fragment が存在する場合、
        //Fragment は新規作成されず、既にインスタンス化してある Fragment が再表示される。
        tx.add(R.id.layout_fragment_1, fragment1, "layout_fragment_1");
        tx.add(R.id.layout_fragment_2, fragment2, "layout_fragment_2");
        // 
        tx.commit();
    }
 
}
実行結果は次のようになります。



以上です(`・ω・´)ゞビシッ!!

参考URL

0 件のコメント:

コメントを投稿