hyoromoのブログ

最近はVRSNS向けに作ったものについて書いています

AlertDialogクラスについて

アプリ開発していると、ユーザー認証用ダイアログを表示させたいと思うでしょう。
私もそう思い、実装してみました。

実装イメージ

以下のようなダイアログが表示されるソースコードを公開します。
コード内では、OKボタンが押されたら EditText 内の文字列を使って URL を作成しています。
dialog

ソース

メインとなる AlertDialog クラスの実装方法
private Dialog setNameDialog() {
    LayoutInflater factory = LayoutInflater.from(this);
    final View entryView = factory.inflate(R.layout.dialog_entry, null);

    return new AlertDialog.Builder(this)
    .setIcon(R.drawable.icon)
    .setTitle("Set tumblr user name.")
    .setView(entryView)
    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            mProgressDialog = ProgressDialog.show(mContext, "Loading",
                    "Image downloading...", true);
            EditText edit = (EditText) entryView.findViewById(R.id.username_edit);
            String url = "http://" + edit.getText().toString() + ".tumblr.com/";
            mTask = new ImageTask().execute(url);
        }
    })
    .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            finish();
        }
    })
    .create();
}

ポイントは username_edit の呼び方。
この widget は context 上には存在しませんので、

  • findViewById(R.id.username_edit);
  • LayoutInflater.from(mContext).inflate(R.layout.username_edit, null);

としても、null や エラーになってしまいます。
そこで、
entryView.findViewById(R.id.username_edit);
と、username_edit が乗っている view をレシーバとして呼び出すと欲しい情報が取ってこれます。

Dialog の呼び出し方法
mContext = this;
setNameDialog().show();

呼び出したい箇所に追加すれば良いのですが、ここで一つポイントがあります。
Activity 上にフォーカスが当たっていれば「this = Activity」ですが、今回の場合はフォーカスが Dialog に当たっているため「this ≠ Activity」となります。
その場合でも Activity で実行したことにしたい場合は、this をクラス変数へ参照渡ししておけばOKです。

xml定義ファイル
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <TextView
        android:id="@+id/dialog_view"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_marginLeft="20dip"
        android:layout_marginRight="20dip"
        android:text="@string/dialog_name"
        android:gravity="left"
        android:textAppearance="?android:attr/textAppearanceMedium" />
    <EditText
        android:id="@+id/username_edit"
        android:text="hyoromo"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:layout_marginLeft="20dip"
        android:layout_marginRight="20dip"
        android:scrollHorizontally="true"
        android:autoText="false"
        android:capitalize="none"
        android:gravity="fill_horizontal"
        android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>

main.xml とは別に作成しています。
Dialog 上の widget のため、id.dialog_view と id.username_edit は Activity から参照できません。

まとめ

entryView.findViewById(R.id.username_edit) と言う方法が出てこなくて、何時間もハマってしまいました。
今現在の状態を確認する事がデバッグへの最短距離だと言うことを改めて教えられたような気がします。

参考

AppDemos > src > com.example.android.apis.app.AlertDialogSamples.java
一通りの Dialog サンプルコードが公開してあり、大変参考になりました。