Проблема раздувания пользовательского представления для AlertDialog в DialogFragment
Я пытаюсь создать DialogFragment
, используя пользовательский вид в AlertDialog
. Это представление должно быть завышено от xml. В моем классе DialogFragment
у меня есть:
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle("Title")
.setView(getActivity().getLayoutInflater().inflate(R.layout.dialog, null))
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, null)
.create();
}
Я пробовал другие методы инфляции для .setView()
, например:
.setView(getActivity().getLayoutInflater().inflate(R.layout.dialog, (ViewGroup) getView(), false))
и
.setView(getActivity().getLayoutInflater().inflate(R.layout.dialog, (ViewGroup) getTargetFragment().getView(), false))
После установки целевого фрагмента в фрагменте, который показывает это диалоговое окно.
Все эти попытки раздуть мое пользовательское представление приводят к следующему исключению:
E/AndroidRuntime(32352): android.util.AndroidRuntimeException: requestFeature() must be called before adding content
E/AndroidRuntime(32352): at com.android.internal.policy.impl.PhoneWindow.requestFeature(PhoneWindow.java:214)
E/AndroidRuntime(32352): at com.android.internal.app.AlertController.installContent(AlertController.java:248)
E/AndroidRuntime(32352): at android.app.AlertDialog.onCreate(AlertDialog.java:314)
E/AndroidRuntime(32352): at android.app.Dialog.dispatchOnCreate(Dialog.java:335)
E/AndroidRuntime(32352): at android.app.Dialog.show(Dialog.java:248)
E/AndroidRuntime(32352): at android.support.v4.app.DialogFragment.onStart(DialogFragment.java:339)
E/AndroidRuntime(32352): at android.support.v4.app.Fragment.performStart(Fragment.java:1288)
E/AndroidRuntime(32352): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:873)
E/AndroidRuntime(32352): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1041)
E/AndroidRuntime(32352): at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:625)
E/AndroidRuntime(32352): at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1360)
E/AndroidRuntime(32352): at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:411)
E/AndroidRuntime(32352): at android.os.Handler.handleCallback(Handler.java:587)
E/AndroidRuntime(32352): at android.os.Handler.dispatchMessage(Handler.java:92)
E/AndroidRuntime(32352): at android.os.Looper.loop(Looper.java:132)
E/AndroidRuntime(32352): at android.app.ActivityThread.main(ActivityThread.java:4028)
E/AndroidRuntime(32352): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(32352): at java.lang.reflect.Method.invoke(Method.java:491)
E/AndroidRuntime(32352): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844)
E/AndroidRuntime(32352): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
E/AndroidRuntime(32352): at dalvik.system.NativeStart.main(Native Method)
Пока я пытаюсь использовать DialogFragment
getLayoutInflator(Bundle)
следующим образом:
.setView(getLayoutInflater(savedInstanceState).inflate(R.layout.dialog, null))
Я получаю StackOverflowError
.
Кто-нибудь знает, как раздуть пользовательский вид для AlertDialog
в DialogFragment
?
Ответы
Ответ 1
Первая строка ошибки дает мне подсказку, что это связано с тем, как вы создаете свой диалог, а не с самим диалогом.
Создаете ли вы диалог автоматически (что может означать, что он вызывается до того, как все настроены) или в ответ на нажатие кнопки? У меня изначально возникли проблемы с фрагментами из-за порядка создания экземпляров.
Я использовал тот же код для установки вида, как и у вас, и мой результат работает. Я вырезал другую настройку, чтобы сделать этот вид более чистым, но он работает с ним или без него.
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_layout, null);
builder.setView(view);
return builder.create();
}
Ответ 2
Меня удивляют эти ответы, так как никто из них не решает проблему.
A DialogFragment позволяет повторно использовать один и тот же интерфейс для обоих диалоговых окон и интегрироваться в ваше приложение в другом месте в виде фрагмента. Довольно полезная функция. Согласно документации Google, вы можете добиться этого, переопределив onCreateDialog и onCreateView.
http://developer.android.com/reference/android/app/DialogFragment.html
Здесь есть три сценария:
- Только переопределить onCreateDialog - работает как диалог, но не может быть
интегрированы в другое место.
- Только переопределение onCreateView - не работает как диалог, но может быть
интегрированы в другое место.
- Отменить оба - Работает как диалог и может быть интегрирован
в другом месте.
Решение:
Класс AlertDialog вызывает другой класс, который вызывает requestFeature. Чтобы исправить это. Не используйте AlertDialog, вместо этого используйте обычный диалог или что-то вроде super.onCreateDialog. Это решение, которое я нашел, работает лучше всего.
Протест:
Другие диалоги, такие как DatePickerDialog, ProgressDialog, TimePickerDialog, все наследуются от AlertDialog и, вероятно, будут вызывать такую же ошибку.
Нижняя линия:
DialogFragment хорош, если вам нужно создать очень настраиваемый интерфейс, который необходимо использовать в нескольких местах. Кажется, он не работает, чтобы повторно использовать существующие диалоги для Android.
Ответ 3
Избегайте сбоя функции запроса и используйте тот же макет:
public class MyCombinedFragment extends DialogFragment
{
private boolean isModal = false;
public static MyCombinedFragment newInstance()
{
MyCombinedFragment frag = new MyCombinedFragment();
frag.isModal = true; // WHEN FRAGMENT IS CALLED AS A DIALOG SET FLAG
return frag;
}
public MyCombinedFragment()
{
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
if(isModal) // AVOID REQUEST FEATURE CRASH
{
return super.onCreateView(inflater, container, savedInstanceState);
}
else
{
View view = inflater.inflate(R.layout.fragment_layout, container, false);
setupUI(view);
return view;
}
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
AlertDialog.Builder alertDialogBuilder = null;
alertDialogBuilder = new AlertDialog.Builder(getActivity());
View view = getActivity().getLayoutInflater().inflate(R.layout.fragment_layout, null);
alertDialogBuilder.setView(view);
alertDialogBuilder.setTitle("Modal Dialog");
alertDialogBuilder.setPositiveButton("Cancel", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
dialog.dismiss();
}
});
setupUI(view);
return alertDialogBuilder.create();
}
}
Ответ 4
У меня была та же проблема. В моем случае это было потому, что Android Studio создала шаблон onCreateView, который заново завысил новый вид вместо того, чтобы возвращать представление, созданное в onCreateDialog. onCreateView вызывается после onCreateDialog, поэтому решение было просто отменить представление фрагментов.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return this.getView();
}
Ответ 5
Столкнулась с той же проблемой, и потребовалось много времени, чтобы избавиться от ошибки. Наконец, проблема с идентификатором ресурса для метода setView() решила проблему. Добавьте установочный вид, как показано ниже:
.setView(R.layout.dialog)
Ответ 6
В коде, где вы вызываете
create().
Заменить
show().
Ответ 7
Я не завышал XML, но я успешно создал динамическое представление в диалоговом окне DialogFragment:
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
m_editText = new EditText(getActivity());
return new AlertDialog.Builder(getActivity())
.setView(m_editText)
.setPositiveButton(android.R.string.ok,null)
.setNegativeButton(android.R.string.cancel, null);
.create();
}
Ответ 8
Вместо этого вы создадите свое собственное представление в методе onCreateView, как обычно. Если вы хотите сделать что-то вроде изменения названия диалогового окна, вы делаете это в onCreateView.
Вот пример, иллюстрирующий, что я имею в виду:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().setTitle("hai");
View v = inflater.inflate(R.layout.fragment_dialog, container, false);
return v;
}
Затем вы просто вызываете:
DialogFragment df = new MyDialogFragment();
df.show(..);
И voila, диалог с вашим собственным пользовательским представлением.
Ответ 9
Поскольку мне было нужно много времени для решения одной и той же проблемы (всплыл простой текстовый диалог), я решил поделиться своим решением:
Макетный файл connectivity_dialog.xml содержит простой TextView с текстом сообщения:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:text="Connectivity was lost"
android:textSize="34sp"
android:gravity="center"
/>
</RelativeLayout>
Активность, показывающая "диалог", реализует внутренний класс (так как DialogFragment - это фрагмент, а не диалог, подробнее см. fooobar.com/info/53591/...). Действие может активировать и деактивировать диалоговое окно с помощью двух функций. Если вы используете android.support.v4, вы можете изменить на getSupportFragmentManager():
public static class ConnDialogFragment extends DialogFragment {
public static ConnDialogFragment newInstance() {
ConnDialogFragment cdf = new ConnDialogFragment();
cdf.setRetainInstance(true);
cdf.setCancelable(false);
return cdf;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.connectivity, container, false);
}
}
private void dismissConn() {
DialogFragment df = (DialogFragment) getFragmentManager().findFragmentByTag("conn");
if (df != null) df.dismiss();
}
private void showConn() {
FragmentTransaction ft = getFragmentManager().beginTransaction();
Fragment prev = getFragmentManager().findFragmentByTag("conn");
if (prev != null) ft.remove(prev);
ft.addToBackStack(null);
ConnDialogFragment cdf = ConnDialogFragment.newInstance();
cdf.show(ft, "conn");
}