Android Tips #29 Android 1.6 から ListFragment と DialogFragment を使う

catch

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

前回は Android 1.6 から Fragment を使う基本について解説しました。今回は Fragment のサブクラスである ListFragment DialogFragment の使いかたについて解説したいと思います!

ListFragment でリストを表示する

1. FragmentActivity を継承した Activity をつくる

前回同様 FragmentActivity を継承した Activity を作成します。Fragment を扱う場合は必ず FragmentActivity を継承しなければいけません。

2. ListFragment をインスタンス化して Adapter をセットする

次に ListFragment に表示するアイテムリストの Adapter をつくります。まずは普通に String の ArrayAdapter をつくってみます。アイテムのレイアウトは標準で用意されている android.R.layout.simple_list_item_1 を使いました。
そして ListFragment をインスタンス化し、 setAdapter() でつくった Adapter をセットします。

ArrayAdapter<String> adapter = new ArrayAdapter<String>(
        this, android.R.layout.simple_list_item_1);
adapter.add("ゴール・D・ロジャー");
adapter.add("モンキー・D・ルフィ");
adapter.add("モンキー・D・ガープ");
adapter.add("モンキー・D・ドラゴン");
adapter.add("ポートガス・D・エース");
adapter.add("マーシャル・D・ティーチ");
adapter.add("ハグワール・D・サウロ");

ListFragment frag = new ListFragment();
frag.setListAdapter(adapter);

3. レイアウトに追加する

つくった ListFragment をレイアウトに追加します。FragmentActivity#getSupportFragmentManager() で FragmentManager を呼び出し、 FragmentManager#beginTransaction() で FragmentTransaction を呼び出します。FragmentTransaction#add() でレイアウトに追加、 commit() して終わりです!

FragmentManager manager = getSupportFragmentManager();
FragmentTransaction tx = manager.beginTransaction();
tx.add(android.R.id.content, frag, "list_fragment");
tx.commit();

list

DialogFragment でダイアログを表示する

1. DialogFragment を継承したカスタムクラスをつくる

まず、DialogFragment を継承したカスタムクラスをつくりましょう。継承元のクラスは android.support.v4.app.DialogFragment です。android.app.DialogFragment ではないので注意しましょう。

dialog01

そして onCreateDialog() をオーバーライドし、その中で Dialog をつくります。Dialog の作りかたは以前までと同様です。

package jp.classmethod.android.sample.dialogfragment;

import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;

public class AlertDialogFragment extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle("タイトル");
        builder.setMessage("メッセージ");
        builder.setPositiveButton(android.R.string.ok, null);
        builder.setNegativeButton(android.R.string.cancel, null);

        return builder.create();
    }

}

2. FragmentActivity を継承した Activity をつくる

ListFragment のときと同様、 FragmentActivity を継承した Activity をつくります。

3. DialogFragment をインスタンス化し show() メソッドを呼ぶ

最後に作成した DialogFragment クラスをインスタンス化し、 DialogFragment#show() を呼ぶと Dialog が表示されます。このときの引数には getSupportFragmentManager() か getSupportFragmentManager().beginTransaction() を渡します。

AlertDialogFragment frag = new AlertDialogFragment();
frag.show(getSupportFragmentManager(), "alert_dialog_fragment");

dialog02

showDialog() は非推奨!

これまでは Activity#showDialog() で表示していましたが、こちらは非推奨となったため Warning が出るようになっています。

dialog03

ダイアログを表示したい場合は DialogFragment を使って実装しましょう。

ListFragment で選択したアイテムを DialogFragment で表示する

最後に、合わせ技してみました。ListFragment で選択されたアイテムを DialogFragment で Bundle で渡して表示するサンプルです。DialogFragment とのデータの受け渡しは Bundle でやりとりします。DialogFragment を呼ぶ側から setArgments() でセットし、DialogFragment 側からは onCreateDialog() 内で getArgments() を呼んで取得します。ListFragment#getListView() をしているタイミングは onPostCreate() になっているのは onCreate() のときにはまだ ListView がないので NullpointerException が発生してしまうためです。

MainActivity.java

package jp.classmethod.android.sample.dialogfragment;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ListFragment;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;

public class MainActivity extends FragmentActivity {

    private ListFragment mFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // ListFragment に渡す ArrayAdapter を作成
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                this, android.R.layout.simple_list_item_1);
        adapter.add("ゴール・D・ロジャー");
        adapter.add("モンキー・D・ルフィ");
        adapter.add("モンキー・D・ガープ");
        adapter.add("モンキー・D・ドラゴン");
        adapter.add("ポートガス・D・エース");
        adapter.add("マーシャル・D・ティーチ");
        adapter.add("ハグワール・D・サウロ");

        // ListFragment を作成し Adapter をセット
        mFragment = new ListFragment();
        mFragment.setListAdapter(adapter);

        // ListFragment をレイアウトに追加
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction tx = manager.beginTransaction();
        tx.add(android.R.id.content, mFragment, "list_fragment");
        tx.commit();
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);

        // アイテムをタップしたときの動作
        mFragment.getListView().setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
                // 対象のアイテムを取得
                String name = (String) mFragment.getListAdapter().getItem(position);

                // Bundle を作成
                Bundle bundle = new Bundle();
                bundle.putString("name", name);

                // DialogFragment を表示
                AlertDialogFragment dialog = new AlertDialogFragment();
                dialog.setArguments(bundle);
                dialog.show(getSupportFragmentManager(), "alert_dialog_fragment");
            }
        });
    }

}

DialogFragment.java

package jp.classmethod.android.sample.dialogfragment;

import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;

public class AlertDialogFragment extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        
        // Bundle からデータを取得
        String name = getArguments().getString("name");

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle("タイトル");
        builder.setMessage(name);
        builder.setPositiveButton(android.R.string.ok, null);
        builder.setNegativeButton(android.R.string.cancel, null);

        return builder.create();
    }

}

実行結果
frag

まとめ

今回は簡単ではありますが ListFragment と DialogFragment についての Support Package を使った実装方法を解説しました。
ListFragment を使うと ListView を Fragment 化したいときに非常に簡単に実装できます。Fragment はこれからのレイアウト作りに欠かせないので、リストを使いたいときにはぜひ活用していきましょう! いっぽうダイアログを表示したいときは Activity#showDialog() が非推奨になっているので DialogFragment を使うようにしましょう。

  • Hideai Minami

    なかなか2.X系のユーザーさんもまだいらっしゃるので、Fragmentシリーズを助かります。
    ちなみに
    new AleratDialog.BuliderとDialogFragmentでの作成は、どちらがいいのでしょうか?

    • suwa.yuki

      いつもコメントいただきありがとうございます!

      AlertDialog.Builder で直接生成する場合と DialogFragment を通して生成する場合の違い、という意味の質問と捉えてよろしいでしょうか?

      Fragment を使うと、Activity 同様、ライフサイクルに準じて実装することになります。

      例えば端末の Portrait と Landscape を切り替えたときなどに Fragment の生成・破棄が行われますが、Fragment のライフサイクルメソッドに合わせて適切にデータをセットしたり、処理を行うことによって、正しく Dialog が表示できるようになります。

      そのため、記事内では onCreateDialog() の中で AlertDialog.Builder から生成するようにしています。

      Dialog の生成する方法は DialogFragment を使う方法が推奨されているので、DialogFragment を採用したほうが良いと思います。

      • Hideai Minami

        ご回答ありがとうございます!
        DialogFragmentで生成したほうが、やっぱりいいのですね~。

        showdialog();で、表示するダイアログの種類を切り替えていたので、非推薦になってしまったので
        どうするか分からず、その場で直接生成していましたw

        Bundleでセットして、取り出せば切り替えることができますね!
        これからはDialogFragmentを使用していきたいと思います!