Як реалізувати спеціальний перегляд 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.