フラグメントのサンプルコード


2014年4月12日現在、私が理解している内容です。
間違っている場合があります。


APIレベル4以上で動く(?)フラグメントのサンプルコード

フラグメントの使い方はよくわからないのですが、
とりあえず、動くだけ、といったサンプルコードを準備する必要があるなあ、ということで用意したものです。

ボタンを押すと、テキストが変わります。




「フラグメントテスト」と表示しているのは、アクティビティの本体で、
ボタンを表示してるのは、フラグメントです。
たぶん、そういう使い方はしないと思いますが、とりあえずテストということで。




「android-support-v4.jar」ライブラリの確認


まずはじめに、「android.support.v4.app.FragmentActivity」をインポートしています。

APIレベル4以上(android1.6以上)でフラグメントが使えるライブラリというものらしいですが、
android1.6で動作確認はしてません。

たぶん、プロジェクトの中の「libs」フォルダにある、
「android-support-v4.jar」が、ライブラリ本体だと思います。
無い場合は、インポートが必要です。

「メニュー>ウィンドウ>Android SDKマネージャー」を選択。



Android SDKマネージャーで、Extrasの中の、「Android Support Library」にチェックをいれてダウンロードします。



「android-sdk」の中の方に「android-support-v4.jar」がダウンロードされているはずですので、
プロジェクトに「libs」というフォルダを作り、「android-support-v4.jar」をコピーします。



パッケージ・エクスプローラーでプロジェクトを選択した後、
「メニュー>ファイル>プロパティ」を開きます。



「Javaのビルド・パス>ライブラリータブ>jar追加」で、
「libs」フォルダの中の、「android-support-v4.jar」を選択します。









「android.support.v4.app.FragmentActivity」をインポートしてフラグメントを使う


「android.support.v4.app.FragmentActivity」をインポートしたときは、
最初の行で、「extends FragmentActivity」とします。

最新のeclipseが生成したコードを元に改造したものです。
特に意味は無いですが、ボタンの設定などは、XMLに記述してなくて、Javaのソースコードに直接書いています。
XMLを使用する場合は、こちらで書き足したところを削除して、コメントアウトした所を復活させてください。

MainActivity.java

package com.example.test03; import android.support.v4.app.FragmentActivity; //APIレベル4以上でフラグメントサポート import android.support.v4.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; public class MainActivity extends FragmentActivity { private static final int LAYOUT_ID1 = 777; public static TextView text1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main); FrameLayout F_layout1 = new FrameLayout(this); F_layout1.setId(LAYOUT_ID1); setContentView(F_layout1); text1 = new TextView(this); text1.setText("フラグメントテスト"); F_layout1.addView(text1); if (savedInstanceState == null) { //getSupportFragmentManager().beginTransaction() // .add(R.id.container, new PlaceholderFragment()).commit(); getSupportFragmentManager().beginTransaction() .add(LAYOUT_ID1, new PlaceholderFragment()).commit(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } /** * A placeholder fragment containing a simple view. */ /* public static class PlaceholderFragment extends Fragment { public PlaceholderFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, false); return rootView; } } */ public static class PlaceholderFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { LinearLayout L_layout1 = new LinearLayout(getActivity()); Button button1 = new Button(getActivity()); button1.setText("ボタンを押す"); //レイアウト上のボタンの表示位置指定 LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); layoutParams.setMargins(0, 200, 0, 0); button1.setLayoutParams(layoutParams); L_layout1.addView(button1); //----------------------------------------- //ボタンが押されたかどうか監視する button1.setOnClickListener( new OnClickListener() { //ボタンが押されたら何かする @Override public void onClick(View v) { text1.setText("ボタンが押されました"); } }); //----------------------------------------- return L_layout1; } } }






「android.support.v7.app.ActionBarActivity」をインポートしてフラグメントを使う


フラグメントと「アクションバー」という便利な機能を使いたい場合は、それ用のライブラリを追加して、
「android.support.v7.app.ActionBarActivity」をインポートします。





「android.support.v7.app.ActionBarActivity」をインポートしたときは、
最初の行で、「extends ActionBarActivity」とします。

APIレベル7以上(android2.1以上)でフラグメントと、アクションバーが使えるライブラリというものらしいですが、
android2.1で動作確認はしてません。

最新のeclipse開発環境を整えてる場合は、すでに使用可能です。
ただ、プロジェクト・エクスプローラーに、「appcompat_v7」がどんどん追加されて収拾がつかないという若干の問題があるようなので、
最新のeclipse開発環境ではなく、SDKとADTのバージョンを22.3にしてる方も多くいらっしゃるようです。私もですが。

ライブラリは「android-support-v7-appcompat.jar」だと思いますので、無い場合は追加してください。
しかしながら、「android-support-v7-appcompat.jar」の無い環境に後から追加した場合、うちだとエラーが出て、
動作確認できなかったので、すこし検証が必要なので、このバージョンはしばらく使わない方針でいこうかと思います。


MainActivity.java

package com.example.test03; import android.support.v7.app.ActionBarActivity; //APIレベル7以上でアクションバーを使う import android.support.v7.app.ActionBar; import android.support.v4.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; import android.view.View.OnClickListener; public class MainActivity extends ActionBarActivity { private static final int LAYOUT_ID1 = 777; public static TextView text1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main); FrameLayout F_layout1 = new FrameLayout(this); F_layout1.setId(LAYOUT_ID1); setContentView(F_layout1); text1 = new TextView(this); text1.setText("フラグメントテスト"); F_layout1.addView(text1); if (savedInstanceState == null) { //getSupportFragmentManager().beginTransaction() // .add(R.id.container, new PlaceholderFragment()).commit(); getSupportFragmentManager().beginTransaction() .add(LAYOUT_ID1, new PlaceholderFragment()).commit(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } /** * A placeholder fragment containing a simple view. */ /* public static class PlaceholderFragment extends Fragment { public PlaceholderFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, false); return rootView; } } */ public static class PlaceholderFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { LinearLayout L_layout1 = new LinearLayout(getActivity()); Button button1 = new Button(getActivity()); button1.setText("ボタンを押す"); //レイアウト上のボタンの表示位置指定 LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); layoutParams.setMargins(0, 200, 0, 0); button1.setLayoutParams(layoutParams); L_layout1.addView(button1); //----------------------------------------- //ボタンが押されたかどうか監視する button1.setOnClickListener( new OnClickListener() { //ボタンが押されたら何かする @Override public void onClick(View v) { text1.setText("ボタンが押されました"); } }); //----------------------------------------- return L_layout1; } } }





APIレベル11以後(android3.0以後)で、フラグメントを使う


この場合は、特別なライブラリを追加しなくてもいい感じです。
ただ、APIレベル11以後(android3.0以後)対応というアプリになります。


最初の行で、「extends Activity」とします。
getSupportFragmentManager()を、
getFragmentManager()に書き換えます。

AndroidManifest.xmlで、以下のAPIレベル11以後対応の設定に書き換えます。


android:minSdkVersion="11"


これを忘れるとエラーになります。
APIレベル11以後の端末に設定したエミュレーターで動作確認してください。


MainActivity.java

package com.example.test03; import android.app.Activity; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; public class MainActivity extends Activity { private static final int LAYOUT_ID1 = 777; public static TextView text1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main); FrameLayout F_layout1 = new FrameLayout(this); F_layout1.setId(LAYOUT_ID1); setContentView(F_layout1); text1 = new TextView(this); text1.setText("フラグメントテスト"); F_layout1.addView(text1); if (savedInstanceState == null) { //getSupportFragmentManager().beginTransaction() // .add(R.id.container, new PlaceholderFragment()).commit(); getFragmentManager().beginTransaction() .add(LAYOUT_ID1, new PlaceholderFragment()).commit(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } /** * A placeholder fragment containing a simple view. */ /* public static class PlaceholderFragment extends Fragment { public PlaceholderFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, false); return rootView; } } */ public static class PlaceholderFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { LinearLayout L_layout1 = new LinearLayout(getActivity()); Button button1 = new Button(getActivity()); button1.setText("ボタンを押す"); //レイアウト上のボタンの表示位置指定 LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); layoutParams.setMargins(0, 200, 0, 0); button1.setLayoutParams(layoutParams); L_layout1.addView(button1); //----------------------------------------- //ボタンが押されたかどうか監視する button1.setOnClickListener( new OnClickListener() { //ボタンが押されたら何かする @Override public void onClick(View v) { text1.setText("ボタンが押されました"); } }); //----------------------------------------- return L_layout1; } } }





AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.test03" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.test03.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>






さらにコンパクトな雛形(APIレベル4以上)





「android.support.v4.app.FragmentActivity」をインポートしています。
MainActivity.javaと、フラグメント用のFragmentF1.javaに別けています。


MainActivity.java

package com.example.test04; import android.support.v4.app.FragmentActivity; import android.widget.FrameLayout; import android.os.Bundle; import android.graphics.Color; public class MainActivity extends FragmentActivity { private static final int LAYOUT_ID1 = 777; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); FrameLayout F_layout1 = new FrameLayout(this); F_layout1.setId(LAYOUT_ID1); setContentView(F_layout1); //レイアウトの背景を黄色にする F_layout1.setBackgroundColor(Color.argb(128, 255, 255,0)); if ( savedInstanceState == null ) { FragmentF1 fragF1 = new FragmentF1(); getSupportFragmentManager().beginTransaction().add(LAYOUT_ID1, fragF1).commit(); } } }


FragmentF1.java

package com.example.test04; import android.support.v4.app.Fragment; //これをインポートすること //import android.app.Fragment; //これをインポートするとエラーになる import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; public class FragmentF1 extends Fragment{ public FragmentF1() {} FragmentF1 getInstance() { FragmentF1 fragment = new FragmentF1(); return fragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { LinearLayout L_layout1 = new LinearLayout(getActivity()); //文字を描画 TextView text1 = new TextView(getActivity()); text1.setText("フラグメントテスト"); L_layout1.addView(text1); return L_layout1; } }


AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.test04" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.test04.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>






基本的なフラグメントの使い方(?)


たとえば、右側の水色の画面に、いろいろ情報を出したいときに、
携帯の縦の画面では、せまくて見え難いですが……。



携帯を横にしたり、タブレットの画面なら、右側の水色の画面を広く使えるようになる、
というのが、フラグメントを使う基本なのですかな?
と、思ったので、サンプルコードを書いてみました。



実際のアプリでは、右側の水色の画面に、いっぱいデータが書き込まれるような使い方になるのでしょう。
端末を回転させたときに、画面は破棄されて、データも再構築されるらしいのですが、
フラグメントのデータは画面回転させても生き続けるので無駄が無いということらしいです。
そういうわけで、右側の水色の画面に、フラグメントのデータを貼り付けてるという感じの作りになってますです。

左の黄色の画面の横幅は、200で固定で指定してますが、画面サイズが異なる端末だと違う見え方になってしまうので、
端末の画面サイズを調べて調整するようにしたほうがいいでしょう。
「FragmentF1.java」の変更はありません。

サポートライブラリを使う場合は、「import android.support.v4.app.Fragment;」をインポートすること。
「import android.app.Fragment;」ではエラーになります。


MainActivity.java

package com.example.test04; import android.support.v4.app.FragmentActivity; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.os.Bundle; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; public class MainActivity extends FragmentActivity { private static final int LAYOUT_ID1 = 777; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //---------------------------------------- //親レイアウト1 LinearLayout L_layout1 = new LinearLayout(this); setContentView(L_layout1); //縦に並ぶ //L_layout1.setOrientation(LinearLayout.VERTICAL); //横に並ぶ L_layout1.setOrientation(LinearLayout.HORIZONTAL); //----------------------------------------- //アイコン画像をビューに読み込む Bitmap image1 = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher); ImageView view1 = new ImageView(this); view1.setImageBitmap(image1); //サイズ LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(200, ViewGroup.LayoutParams.MATCH_PARENT); view1.setLayoutParams(params1); //背景を黄色にする view1.setBackgroundColor(Color.argb(128, 255, 255, 0)); //アイコン画像のビューを親レイアウト1に追加 L_layout1.addView(view1); //-------------------------------------------- //子レイアウト2 LinearLayout L_layout2 = new LinearLayout(this); //子レイアウト2の背景を水色にする L_layout2.setBackgroundColor(Color.argb(255, 0, 255, 255)); //サイズ LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); //子レイアウト2を親レイアウト1に追加 L_layout1.addView(L_layout2,layoutParams2); //-------------------------------------------- //子レイアウト2に、フラグメントを設定するためのID L_layout2.setId(LAYOUT_ID1); if ( savedInstanceState == null ) { FragmentF1 fragF1 = new FragmentF1(); getSupportFragmentManager().beginTransaction().add(LAYOUT_ID1, fragF1).commit(); } } }





フラグメントの挙動のテスト


では、フラグメントの動作って実際どうなの?
って、ことでこんなテストを。
端末を回転させると、フラグメントにデータが追記されていきます。
端末を回転させると、アクティビティが破棄されて、onCreateが呼ばれるわけですが、そのときフラグメントを貼っています。



端末を回転させると、アクティビティは破棄されて再生成されますが、
フラグメントに貼り付けたデータは、保持されてるので、データが追記になる、という感じでしょうか?
フラグメント側で保持してるのではなく、
何をいくつ貼り付けたかを、管理して、破棄されるごとに再生成してるのが「FragmentManager」「Transaction」なるものか。





MainActivity.java

package com.example.test05; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.os.Bundle; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; public class MainActivity extends FragmentActivity { private static final int LAYOUT_ID1 = 777; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //---------------------------------------- //親レイアウト1 LinearLayout L_layout1 = new LinearLayout(this); setContentView(L_layout1); //横に並ぶ L_layout1.setOrientation(LinearLayout.HORIZONTAL); //----------------------------------------- //アイコン画像をビューに読み込む Bitmap image1 = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher); ImageView view1 = new ImageView(this); view1.setImageBitmap(image1); //サイズ LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(200, ViewGroup.LayoutParams.MATCH_PARENT); view1.setLayoutParams(params1); //背景を黄色にする view1.setBackgroundColor(Color.argb(255, 255, 255, 0)); //アイコン画像のビューを親レイアウト1に追加 L_layout1.addView(view1); //-------------------------------------------- //子レイアウト2 LinearLayout L_layout2 = new LinearLayout(this); //子レイアウト2の背景を水色にする L_layout2.setBackgroundColor(Color.argb(255, 0, 255, 255)); //子レイアウト2は縦に並ぶ L_layout2.setOrientation(LinearLayout.VERTICAL); //サイズ LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); //子レイアウト2を親レイアウト1に追加 L_layout1.addView(L_layout2,layoutParams2); //-------------------------------------------- //子レイアウト2に、フラグメントを設定するためのID L_layout2.setId(LAYOUT_ID1); //フラグメントに描画していく Put_fragment1(); } public void Put_fragment1(){ //FragmentManagerを設定 FragmentManager manager = getSupportFragmentManager(); //Transactionを設定 FragmentTransaction ft = manager.beginTransaction(); //---------------------------------- //フラグメントに貼るデータを作る FragmentF1 frag1 = new FragmentF1(); Bundle bd1 = new Bundle(); bd1.putString("data1", "フラグメントデータ"); //フラグメントにバンドルを渡す frag1.setArguments(bd1); //---------------------------------- //フラグメントに追加する ft.add(LAYOUT_ID1, frag1); //Fragmentの変化時のアニメーションを指定 ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); ft.commit(); } }





FragmentF1.java

package com.example.test05; import android.support.v4.app.Fragment; //これをインポートすること //import android.app.Fragment; //これをインポートするとエラーになる import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; public class FragmentF1 extends Fragment{ public FragmentF1() {} @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //レイアウトを作る LinearLayout layout1 = new LinearLayout(getActivity()); //Bundleのデータ読み込み String moji1 = getArguments().getString("data1"); //----------------------------------------- //アイコン画像を読み込み Bitmap img1 = BitmapFactory.decodeResource( getResources(),R.drawable.ic_launcher); //アイコン画像を貼り付ける画面 ImageView imgvw1 = new ImageView(getActivity()); //背景色 imgvw1.setBackgroundColor(Color.argb(255, 255, 0, 0)); //画面にアイコン画像をセット imgvw1.setImageBitmap(img1); //サイズをセット LayoutParams para1 = new LayoutParams(50,50); //画面のサイズをセット imgvw1.setLayoutParams(para1); //アイコンを描画した画面を並べる layout1.addView(imgvw1); //----------------------------------------- //テキストを貼り付ける画面 TextView text = new TextView(getActivity()); //テキストをセット text.setText(moji1); //テキストを並べる layout1.addView(text); return layout1; } }














戻る