Як реалізувати спеціальний перегляд AlertDialog


107

У Документах Android на AlertDialog він подає таку інструкцію та приклад для встановлення спеціального перегляду в AlertDialog:

Якщо ви хочете відобразити більш складний вигляд, знайдіть FrameLayout під назвою "body" і додайте до нього свій погляд:

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

По-перше, досить очевидно, що add()це друкарська помилка addView().

Мене бентежить перший рядок із використанням R.id.body. Здається, що це елемент тіла AlertDialog ... але я не можу просто ввести, що в моєму коді b / c він дає помилку компіляції. Де Р.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();

Щоб знайти та використовувати об’єкти в діалоговому вікні, виконайте цей чотири кроки: stackoverflow.com/a/18773261/1699586
— Сара,

3
Однорядкова відповідь: додати .setView(getLayoutInflater().inflate(R.layout.dialog_view, null))до будівельника. Кредит Серджіо Віудесса нижче.
— 1 ''

Відповіді:


49

Ви маєте рацію, тому що ви її вручну не роздували. Схоже, ви намагаєтесь "витягнути" ідентифікатор "body" з макета своєї діяльності, і це не вийде.

Ви, мабуть, хочете щось подібне:

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

17
Цікаво, що тіло не визначається як константа в android.R.id. Мені все ще не зрозуміло, як отримати доступ до елемента 'body' створеного AlertDialog. Я все ще хотів би знати, як це зробити, але поки я просто спробую надути подання та використовувати 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. Що б ви порадили робити в такому випадку, якщо я хотів посилатися на батьків? Єдине, що я бачу в alerDialog, який повертає погляд, це getCurrentFocus ()
— stormin986

5
Тримайся Viewнадутого. Зателефонуйте findViewById()до цього, Viewколи вам потрібні речі з його вмісту. Дивіться: github.com/commonsguy/cw-android/tree/master/Database/Constants
— CommonsWare

159

Ви можете створити свій погляд безпосередньо з Інфраструктури макета, вам потрібно використовувати лише XML-файл вашого макета та ідентифікатор макета у файлі.

Ваш XML-файл повинен мати такий ідентифікатор:

<?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 у цьому прикладі? Це не перегляд у поточній діяльності?
— Олексій Прецлав

5
@AlexPretzlav: dialog_layout_root у цьому прикладі не потрібен. Все, що вам потрібно, - це ім'я вашого файлу xml для R.layout. [Name_of_xml_file].
— ІгорГанапольський

7
@Temperage Ви додали builder.show наприкінці. Я спробував цей код, і він спрацював. Також я передав null як другий параметр для infalter.inflate
— Vinoth

2
Це повинно було бути обрано як найкращий відповідь.
— Салман Хаквані

2
Це дає ClassCastException, коли спеціальний макет містить EditText, тому що getCurrentFocus()поверне EditText і EditText не може бути передано до ViewGroup. Використання nullв якості другого аргументу це виправляє.
— 1 ''

20

android.R.id.custom повертався для мене нульовим. Мені вдалося змусити це працювати, якщо хтось стикається з тим самим питанням,

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 (новий LayoutParams (LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); або щось перше, що запобіжить помилки, яких не очікували
— MOBYTELAB

дякую за відгук .. як ви надуваєте перед builder.create ()? надувати називається надувачем діалогу, і я маю лише діалог, тому що я назвав builder.create ()
— Джон Релліс

ми можемо використовувати надувач активності, а не прикріплювати його до FrameLayout, тому ми можемо зменшити трохи такого коду.AlertDialog.Builder builder = новий AlertDialog.Builder (новий ContextThemeWrapper (getActivity (), android.R.style.Theme_Holo)) .setTitle ("назва") .setIcon (R.dravable.sample_icon); Переглянути проблемуView = inflater.inflate (R.layout.sample_layout, null, false); builder.setView (errorView); alert = builder.create (); Вибачте, я не знаю, як чітко написати код на коментарі
— MOBYTELAB

Йдеться лише про помилку в дизайні, якщо ми зібраємо все в макеті xml і забудемо Framelayout як корінь діалогу, ми можемо бути цікавими, якщо макет у xml не заповнить батьківський або щось подібне, а лише випадок.
— MOBYTELAB

Працювали для мене, дякую! Цей дозволяє мені додати заголовок та кнопку Скасувати та Гаразд, включаючи EditText без помилок. :) Питання лише в тому, як це працює? Чи FrameLayoutвиступає в ролі фрагменту? Коли я спробував відповідь Andrewx2 вище, я отримав помилку, оскільки вважав, що я завищую два макети (це моя здогадка).
— Azurespot



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 може зробити висновок про тип. Це дуже приємна особливість. Це допомагає чистити код багато.
— Сурагч

чудова відповідь, дуже корисна
— Noor Hossain

4

Найпростіші рядки коду, які працюють для мене, такі:

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

Незалежно від типу компонування (LinearLayout, FrameLayout, RelativeLayout) буде працювати setView і просто відрізнятиметься за зовнішнім виглядом та поведінкою.


приголомшливий, простий і легкий
— Франк Ено

2

Найпростіший спосіб зробити це, використовуючи android.support.v7.app.AlertDialogзамість того, android.app.AlertDialogде public AlertDialog.Builder setView (int layoutResId)можна використовувати нижче API 21.

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 з підтримки. Вуаля !!!
— Дібзманія

2

AlertDialog.setView(View view)додає даний вигляд у R.id.custom FrameLayout. Далі наведено фрагмент вихідного коду Android, з AlertController.setupView()якого, нарешті, це обробляється ( mViewце погляд, наданий AlertDialog.setViewметоду).

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

1

Змінивши ідентифікатор it android.R.id.custom, мені потрібно було додати наступне, щоб відобразити перегляд:

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

Однак це призвело до того, що новий вигляд відображається у великому батьківському поданні без фону, розбиваючи діалогове вікно на дві частини (текст і кнопки, з новим представленням між ними). Нарешті я отримав такий ефект, який хотів, вставивши свій Погляд поруч із повідомленням:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.