カスタムAlertDialogビューを実装する方法


107

AlertDialogAndroidドキュメントでは、AlertDialogでカスタムビューを設定するための次の手順と例が示されています。

より複雑なビューを表示したい場合は、「body」というFrameLayoutを検索して、ビューを追加します。

FrameLayout fl = (FrameLayout) findViewById(R.id.body);
fl.add(myView, new LayoutParams(FILL_PARENT, WRAP_CONTENT));

まず、それadd()がタイプミスであり、であることを意図していることはかなり明白ですaddView()

R.id.bodyを使用する最初の行で混乱しています。それはAlertDialogのbody要素のようです...しかし、コードb / cにそれを入力するだけではコンパイルエラーが発生します。R.id.bodyはどこで定義または割り当てられますか?

これが私のコードです。私setView(findViewById(R.layout.whatever)はビルダーで使用しようとしましたが、うまくいきませんでした。手動で膨らませなかったからと思いますか?

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Title")
    .setCancelable(false)
    .setPositiveButton("Go", new DialogInterface.OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int id) {
        EditText textBox = (EditText) findViewById(R.id.textbox);
        doStuff();
    }
});

FrameLayout f1 = (FrameLayout)findViewById(R.id.body /*CURRENTLY an ERROR*/);
f1.addView(findViewById(R.layout.dialog_view));

AlertDialog alert = builder.create();
alert.show();

ダイアログでオブジェクトを見つけて使用するには、次の4つの手順に従います。stackoverflow.com/a/ 18773261
Sara

3
1行の回答:.setView(getLayoutInflater().inflate(R.layout.dialog_view, null))ビルダーに追加します。下記のセルジオヴィウデスの功績です。
1

回答:


49

正解です。手動で膨らませなかったからです。アクティビティのレイアウトから「body」IDを「抽出」しようとしているようですが、これは機能しません。

あなたはおそらくこのようなものを望みます:

LayoutInflater inflater = getLayoutInflater();
FrameLayout f1 = (FrameLayout)alert.findViewById(android.R.id.body);
f1.addView(inflater.inflate(R.layout.dialog_view, f1, false));

17
興味深いことに、bodyはandroid.R.idで定数として定義されていません。作成されたAlertDialogの「body」要素にアクセスする方法については、まだはっきりしていません。これを行う方法を知りたいのですが、今のところは、ビューを膨らませてビルダーでsetViewを使用するだけです。
stormin986

2
実際、これでもまだ質問が残っています(ビューを膨らませるのは初めてです)。を使用してbuilder.setView(inflater.inflate(R.id.dialog, ROOT_VIEWGROUP[, ATTACH_TO_ROOT]))、ドキュメントはルートビューグループはオプションであると言います。この場合、これを使用する必要がありますか?もしそうなら...それでもAlertDialogへの参照を取得する方法を理解する必要があります...
stormin986

2
これはオプションですが、インフレートするレイアウトの内側から親への参照はありません。android:layout_gravityのようなものは、トップレベルのビューでは機能しません...そして、おそらくそれらは必要ありません。AlertDialog alert = builder.create()を呼び出すと、AlertDialogへの参照があります。長い答えは短い、それオプションです。カスタムレイアウトで何をしているかに応じて、試してみてください。おそらく機能します。
シニック

2
AlertDialog内でビューを参照する方法がわかりません。この場合、親を参照したい場合はどうすればよいですか。ビューを返すalertDialog内で私が見る唯一のものはgetCurrentFocus()です
stormin986

5
View膨らませてください。その内容から何かが必要なときfindViewById()にそれを呼び出しViewます。参照:github.com/commonsguy/cw-android/tree/master/Database/Constants
CommonsWare

159

レイアウトインフレータから直接ビューを作成できます。必要なのは、レイアウトXMLファイルの名前とファイル内のレイアウトのIDだけです。

XMLファイルには次のようなIDが必要です。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/dialog_layout_root"
              android:orientation="vertical"
              android:layout_width="fill_parent"
              android:layout_height="wrap_content"
              android:padding="10dp"
              />

次に、次のコードを使用してビルダーでレイアウトを設定できます。

LayoutInflater inflater = getLayoutInflater();
View dialoglayout = inflater.inflate(R.layout.dialog_layout, null);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(dialoglayout);
builder.show();

4
そして、この例のR.id.dialog_layout_rootはどこにありますか?それは現在のアクティビティのビューではありませんか?
Alex Pretzlav、2011

5
@AlexPretzlav:この例では、dialog_layout_rootは必要ありません。必要なのは、R.layout。[name_of_xml_file]のxmlファイルの名前だけです。
IgorGanapolsky

7
@Temperage最後にbuilder.showを追加しましたか。私はこのコードを試してみましたが、うまくいきました。また、infalter.inflateの2番目のパラメーターとしてnullを渡しました
Vinoth

2
これがベストアンサーとして選択されているはずです。
Salman Khakwani 2013

2
これにより、カスタムレイアウトにEditTextが含まれる場合にClassCastExceptionが発生します。これは、EditText getCurrentFocus()が返され、EditTextをViewGroupにキャストできないためです。null2番目の引数として使用すると、これが修正されます。
1

20

android.R.id.customがnullを返していました。誰かが同じ問題に遭遇した場合に備えて、これをうまく動かすことができました。

AlertDialog.Builder builder = new AlertDialog.Builder(context)
            .setTitle("My title")
            .setMessage("Enter password");
final FrameLayout frameView = new FrameLayout(context);
builder.setView(frameView);

final AlertDialog alertDialog = builder.create();
LayoutInflater inflater = alertDialog.getLayoutInflater();
View dialoglayout = inflater.inflate(R.layout.simple_password, frameView);
alertDialog.show();

参考までに、R.layout.simple_passwordは次のとおりです。

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="match_parent"
          android:layout_height="match_parent">

<EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/password_edit_view"
        android:inputType="textPassword"/>
<CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/show_password"
        android:id="@+id/show_password_checkbox"
        android:layout_gravity="left|center_vertical"
        android:checked="false"/>

</LinearLayout>

ジョン・レリス。ソリューションは正常に動作します。それに何かがあるだけです。builder.createの前に膨張し、frameView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT、LayoutParams.WRAP_CONTENT));を設定する必要があります。または何か最初に、予期しないいくつかのバグを防ぐ
MOBYTELAB

フィードバックに感謝します。builder.create()の前にどのように膨張しますか inflateはダイアログのインフレーターで呼び出され、builder.create()を呼び出したのでダイアログしかありません
John Rellis

FrameLayoutにアタッチせずに、アクティビティインフレータを使用できるため、次のような小さなコードを削減できます。AlertDialog.Builderbuilder = new AlertDialog.Builder(new ContextThemeWrapper(getActivity()、android.R.style.Theme_Holo)).setTitle ( "タイトル").setIcon(R.drawable.sample_icon); troubleView = inflater.inflate(R.layout.sample_layout、null、false);を表示します。builder.setView(troubleView); アラート= builder.create(); コメントでコードを明確に書く方法がわかりません
MOBYTELAB 2013

レイアウトのxmlにすべてを収集し、Framelayoutをダイアログのルートとして忘れた場合、それは設計上のバグにすぎません。xmlのレイアウトが親または何かを埋めていないのかどうか、気になることがあります。
MOBYTELAB 2013

私のために働いた、ありがとう!これにより、エラーなしでEditTextを含む、タイトルと[キャンセル]および[OK]ボタンを追加できます。:)唯一の質問は、これはどのように機能するのですか?FrameLayout一種の断片として機能しますか?上記のAndrewx2の回答を試したところ、2つのレイアウトを膨らませていると思ったため、エラーが発生しました(私の推測です)。
Azurespot 2014



8

カスタムAlertDialog

この完全な例には、アクティビティにデータを返すことが含まれます。

ここに画像の説明を入力してください

カスタムレイアウトを作成する

EditTextこの簡単な例では、を使用したレイアウトが使用されていますが、好きなものに置き換えることができます。

custom_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:paddingLeft="20dp"
              android:paddingRight="20dp"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

コードでダイアログを使用する

重要な部分は

  • を使用setViewしてカスタムレイアウトをAlertDialog.Builder
  • ダイアログボタンがクリックされたときに、データをアクティビティに送り返します。

これは、上の画像に示すサンプルプロジェクトの完全なコードです。

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void showAlertDialogButtonClicked(View view) {

        // create an alert builder
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Name");

        // set the custom layout
        final View customLayout = getLayoutInflater().inflate(R.layout.custom_layout, null);
        builder.setView(customLayout);

        // add a button
        builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // send data from the AlertDialog to the Activity
                EditText editText = customLayout.findViewById(R.id.editText);
                sendDialogDataToActivity(editText.getText().toString());
            }
        });

        // create and show the alert dialog
        AlertDialog dialog = builder.create();
        dialog.show();
    }

    // do something with the data coming from the AlertDialog
    private void sendDialogDataToActivity(String data) {
        Toast.makeText(this, data, Toast.LENGTH_SHORT).show();
    }
}

ノート

  • これを複数の場所で使用している場合DialogFragmentは、ドキュメントで説明されているようにサブクラスを作成することを検討してください。

こちらもご覧ください


1
EditText editText = customLayout.findViewById(R.id.editText); あるべき EditText editText = (EditText) customLayout.findViewById(R.id.editText);
philcruz

4
@ philcruz、Android Studio 3.0にアップグレードすると、ビューを明示的にキャストする必要がなくなります。IDEはタイプを推測できます。それはとても素晴らしい機能です。コードのクリーンアップに役立ちます。
Suragch、

すばらしい回答、本当に役立つ
Noor Hossain

4

私にとって機能する最も単純なコード行は次のとおりです。

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(R.layout.layout_resource_id);
builder.show();

レイアウトのタイプ(LinearLayout、FrameLayout、RelativeLayout)が機能setView し、外観と動作が異なるだけです。


素晴らしく、シンプル、そして簡単
Frank Eno

2

これを行う最も簡単な方法は、API 21の下で使用できる場所のandroid.support.v7.app.AlertDialog代わりにを使用することです。android.app.AlertDialogpublic AlertDialog.Builder setView (int layoutResId)

new AlertDialog.Builder(getActivity())
    .setTitle(title)
    .setView(R.layout.dialog_basic)
    .setPositiveButton(android.R.string.ok,
        new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                //Do something
            }
        }
    )
    .setNegativeButton(android.R.string.cancel,
        new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                //Do something
            }
        }
    )
    .create();

API 21が導入された後にこれを読む人は、このメソッドを使用する必要があります。回答が言及しているように、アプリのminSDKversionが21未満の場合は、サポートパッケージのAlerDialogを使用します。出来上がり!!!
Dibzmania 2017

2

AlertDialog.setView(View view)指定されたビューをに追加しますR.id.custom FrameLayout。以下は、AlertController.setupView()最終的にこれを処理するAndroidソースコードのスニペットです(メソッドにmView与えられたビューAlertDialog.setViewです)。

...
FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.**custom**);
custom.addView(**mView**, new LayoutParams(FILL_PARENT, FILL_PARENT));
...

1

IDをandroid.R.id.customに変更した後、ビューを表示するために以下を追加する必要があります。

((View) f1.getParent()).setVisibility(View.VISIBLE);

ただし、これにより、新しいビューが背景のない大きな親ビューでレンダリングされ、ダイアログボックスが2つの部分(テキストとボタン、新しいビューを挟んで)に分割されました。メッセージの横にビューを挿入することで、私はようやく思い通りの効果を得ました。

LinearLayout f1 = (LinearLayout)findViewById(android.R.id.message).getParent().getParent();

この解決策は、View.getParent()およびView.getChildAt(int)を使用してビューツリーを探索することで見つかりました。しかし、どちらについてもあまり満足していません。これはAndroidのドキュメントには含まれておらず、AlertDialogの構造を変更した場合、これが壊れる可能性があります。


1

この方法で行うのが最も理にかなっており、最小限のコードで済みます。

new AlertDialog.Builder(this).builder(this)
        .setTitle("Title")
        .setView(R.id.dialog_view)   //notice this setView was added
        .setCancelable(false)
        .setPositiveButton("Go", new DialogInterface.OnClickListener() {
            @Override 
            public void onClick(DialogInterface dialog, int id) {
                EditText textBox = (EditText) findViewById(R.id.textbox);
                doStuff();
            }
        }).show();

設定できる拡張されたリストについては.set、Android Studioで入力を開始してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.