Как реализовать пользовательское представление AlertDialog
В документах 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. Кажется, что это элемент body AlertDialog ... но я не могу просто указать, что в моем коде 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();
12 ответов
Вы правы, это потому, что вы не раздували это вручную. Похоже, что вы пытаетесь "извлечь" идентификатор "body" из макета вашего Activity, и это не сработает.
Вы, вероятно, хотите что-то вроде этого:
LayoutInflater inflater = getLayoutInflater();
FrameLayout f1 = (FrameLayout)alert.findViewById(android.R.id.body);
f1.addView(inflater.inflate(R.layout.dialog_view, f1, false));
Вы можете создать свое представление непосредственно из Inflater Layout, вам нужно только использовать имя вашего 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();
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>
Документы Android были отредактированы, чтобы исправить ошибки.
Представление внутри AlertDialog называется android.R.id.custom
http://developer.android.com/reference/android/app/AlertDialog.html
Пользовательский AlertDialog
Этот полный пример включает передачу данных обратно в Activity.
Создать собственный макет
Макет с 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
подкласс, как описано в документации.
Смотрите также
Это сработало для меня:
dialog.setView(dialog.getLayoutInflater().inflate(R.layout.custom_dialog_layout, null));
Простейшие строки кода, которые работают для меня, следующие:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(R.layout.layout_resource_id);
builder.show();
Независимо от типа макета (LinearLayout, FrameLayout, RelativeLayout) будет работать setView
и будет просто отличаться по внешнему виду и поведению.
Самый простой способ сделать это с помощью 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();
AlertDialog.setView(View view) добавляет данное представление к R.id.пользовательский FrameLayout. Ниже приведен фрагмент исходного кода Android из AlertController.setupView(), который, наконец, обрабатывает это (mView - это представление, данное методу AlertDialog.setView).
...
FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.**custom**);
custom.addView(**mView**, new LayoutParams(FILL_PARENT, FILL_PARENT));
...
Было бы разумно сделать это таким образом, наименьшее количество кода.
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
После изменения идентификатора на android.R.id.custom мне нужно было добавить следующее, чтобы отобразить представление:
((View) f1.getParent()).setVisibility(View.VISIBLE);
Однако это привело к тому, что новое представление отображалось в большом родительском представлении без фона, разбивая диалоговое окно на две части (текст и кнопки с новым представлением между ними). Я наконец получил эффект, который я хотел, вставив мой вид рядом с сообщением:
LinearLayout f1 = (LinearLayout)findViewById(android.R.id.message).getParent().getParent();
Я нашел это решение, изучив дерево View с помощью View.getParent() и View.getChildAt(int). Хотя и не очень доволен. Ничего из этого нет в документации для Android, и если они когда-либо изменят структуру AlertDialog, это может сломаться.
Это работает для меня! и не забудьте реализовать прослушиватель.
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.add_employee, null);