Androidはワンツーパンチ 三歩進んで二歩下がる

Android卵プログラマーの記録ブログ

DialogFragmentでシンプルで汎用的なダイアログ

自分用のメモです。

AlertDialogをダイアログ表示処理に使っていましたが非推奨になったので
DialogFragmentを使うことにしました。

参考にさせていただいたサイトさま
何故DialogFragmentか
Why DialogFragment can't be an inner class?

DialogFragmentを継承したクラスを作成してその中にダイアログがクリックされた
処理を書けば呼び出し側もソースがすっきりします。
でもちょっとした処理でいちいちソースファイルを増やしたくないし
君はokかキャンセルかだけ返してくれれば後はこっちで処理するからってことも
多いので、使いまわせるシンプルなDialogFragment継承クラスを作ることにしました。

上記の参考サイトさまにも「ActivityやFragmentに専用のInterfaceを実装する」
との項目がありますが、コールバックインタフェースを使って、
okかcancelかのイベントだけ取って後は呼び出し元で処理を行います。
呼び出し元内で複数DialogFragmentを使う時はコールバックメソッドの引数に
リクエストコード的なものを渡してやるように変えればどこから呼び出したかわかりますね。

サンプルの実行イメージはこのような感じです。

ところでgistにあるコードを埋め込みたいんだけどうまくいかないです(;´Д`)
何でだかわからない(;´Д`)

【2013/09/30追記】 gistのスクリプトを貼り付ける時にsrc=の後ろのURLに自分のユーザー名が入っているとうまく表示出来ないようです。 @kimukou_26 さん、教えてくださってありがとうございます。

【2013/09/30追記】 ソースを変更いたしました。Dialogなのにdismiss()してなかったり考慮不足で申し訳ありませんでした。ソースはgithubに載せました。変更前と変更後の比較はDiffにてご覧くださいませ。

/MyExamDialogFragment/src/sakura/example/myexamdialogfragment/CommonDialogFragment.java

package sakura.example.myexamdialogfragment;

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

public class CommonDialogFragment extends DialogFragment {
    private DialogListener listener = null;

    public static CommonDialogFragment newInstance(String title, String message) {
        CommonDialogFragment frag = new CommonDialogFragment();
        Bundle bundle = new Bundle();
        bundle.putString("title", title);
        bundle.putString("message", message);
        frag.setArguments(bundle);
        return frag;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        String title = getArguments().getString("title");
        String message = getArguments().getString("message");

        return new AlertDialog.Builder(getActivity())
                .setIcon(R.drawable.ic_launcher)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton(android.R.string.ok,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int whichButton) {
                                listener.onPositiveClick();
                                dismiss();
                            }
                        }
                )
                .setNegativeButton(android.R.string.cancel,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int whichButton) {
                                listener.onNegativeClick();
                                dismiss();
                            }
                        }
                )
                .create();
    }

    /**
     * リスナーを追加する
     * 
     * @param listener
     */
    public void setDialogListener(DialogListener listener) {
        this.listener = listener;
    }

    /**
     * リスナーを削除する
     */
    public void removeDialogListener() {
        this.listener = null;
    }
}

/MyExamDialogFragment/src/sakura/example/myexamdialogfragment/DialogListener.java

package sakura.example.myexamdialogfragment;

import java.util.EventListener;

public interface DialogListener extends EventListener {

    /**
     * okボタンが押されたイベントを通知する
     */
    public void onPositiveClick();

    /**
     * cancelボタンが押されたイベントを通知する
     */
    public void onNegativeClick();
}

/MyExamDialogFragment/src/sakura/example/myexamdialogfragment/Fragment01.java

package sakura.example.myexamdialogfragment;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;

public class Fragment01 extends Fragment implements OnClickListener, DialogListener {
    // DialogListenerを実装しておく

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (container == null) {
            return null;
        }
        return inflater.inflate(R.layout.fragment01, container, false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        Button button = (Button) getView().findViewById(R.id.button1);
        button.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button1:
                // 以前ゴチャゴチャやってたけどもっとシンプルに書けました。考慮不足で申し訳ありません!
                CommonDialogFragment newFragment = CommonDialogFragment.newInstance(
                        "title", "this is message");
                newFragment.setDialogListener(this);
                newFragment.show(getActivity().getSupportFragmentManager(), "CommonDialogFragment");

                break;

            default:
                break;
        }
    }

    @Override
    public void onPositiveClick() {
        Toast.makeText(getActivity(), "ok ボタンが押された", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onNegativeClick() {
        Toast.makeText(getActivity(), "cancel ボタンが押された", Toast.LENGTH_SHORT).show();
    }

}

/MyExamDialogFragment/src/sakura/example/myexamdialogfragment/MainActivity.java

package sakura.example.myexamdialogfragment;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
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);

        Fragment01 frag = new Fragment01();
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.add(R.id.main, frag, "Fragment01");
        ft.commit();
    }
}

/MyExamDialogFragment/res/layout/activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/main"
    tools:context=".MainActivity" >

</RelativeLayout>

/MyExamDialogFragment/res/layout/fragment01.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="ダイアログを表示する" />

</RelativeLayout>