android - ejemplo - Problema al inflar la vista personalizada para AlertDialog en DialogFragment
alertdialog android personalizado (9)
Estoy intentando crear un DialogFragment
usando una vista personalizada en un AlertDialog
. Esta vista debe estar inflada desde xml. En mi clase DialogFragment
tengo:
@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();
}
He intentado otros métodos de inflación para .setView()
como:
.setView(getActivity().getLayoutInflater().inflate(R.layout.dialog, (ViewGroup) getView(), false))
y
.setView(getActivity().getLayoutInflater().inflate(R.layout.dialog, (ViewGroup) getTargetFragment().getView(), false))
Después de establecer el fragmento de destino en el fragmento que muestra este cuadro de diálogo.
Todos estos intentos de inflar mi vista personalizada dan como resultado la siguiente excepción:
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)
Mientras que si trato de usar DialogFragment
getLayoutInflator(Bundle)
esta manera:
.setView(getLayoutInflater(savedInstanceState).inflate(R.layout.dialog, null))
Obtengo un StackOverflowError
.
¿Alguien sabe cómo inflar una vista personalizada para un AlertDialog
en un DialogFragment
?
Como necesitaba mucho tiempo para resolver el mismo problema (Pop up a simple Text Dialog), decidí compartir mi solución:
El archivo de diseño connectivity_dialog.xml contiene un simple TextView con el texto del mensaje:
<?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>
La Actividad que muestra el "diálogo" implementa una clase interna (como DialogFragment es un Fragmento y no un Diálogo, más información, consulte https://.com/a/5607560/6355541 ). La actividad puede activar y desactivar DialogFragment a través de dos funciones. Si está utilizando android.support.v4, puede querer cambiar a 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");
}
En tu código al que llamas
create().
Reemplazar con
show().
Enfrentó el mismo problema, y tomó mucho tiempo deshacerse del error. Finalmente, pasar el ID del recurso al método setView () resolvió el problema. Agregue la vista de conjunto de la siguiente manera:
.setView(R.layout.dialog)
Evite el bloqueo de la función de solicitud y use el mismo diseño:
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();
}
}
La primera línea de error me da la pista de que esto está relacionado con la forma en que está creando su diálogo, no con el diálogo mismo.
¿Está creando el diálogo automáticamente (lo que podría significar que se llama antes de que todas las vistas estén configuradas) o en respuesta a un clic del botón? Inicialmente tuve problemas con fragmentos debido al orden de creación de instancias.
Usé el mismo código para establecer la vista que tiene, y mi resultado funciona. Corté la otra configuración para que se vea más limpia, pero funciona con o sin ella.
@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();
}
Lo que quiere hacer en su lugar es crear su vista personalizada en el método onCreateView como lo haría normalmente. Si desea hacer algo como cambiar el título del diálogo, hágalo en onCreateView.
Aquí hay un ejemplo para ilustrar lo que quiero decir:
@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;
}
Entonces solo llamas:
DialogFragment df = new MyDialogFragment();
df.show(..);
Y listo, un diálogo con su propia vista personalizada.
Me sorprenden estas respuestas ya que ninguno de ellos resuelve el problema.
Un DialogFragment le permite reutilizar la misma interfaz de usuario para un diálogo e integrarlo en su aplicación como un fragmento. Muy útil. De acuerdo con la documentación de Google, puede lograr esto sobrescribiendo onCreateDialog y onCreateView. http://developer.android.com/reference/android/app/DialogFragment.html
Hay tres escenarios aquí:
- Sobrescribe onCreateDialog only: funciona como un diálogo pero no se puede integrar en ningún otro lugar.
- Anular solo enCreateView: no funciona como un diálogo, pero puede integrarse en cualquier otro lugar.
- Anular ambos: funciona como un diálogo y se puede integrar en cualquier otro lugar.
Solución: la clase AlertDialog llama a otra clase que llama a requestFeature. Para solucionar esto ... No use AlertDialog, en su lugar utilice un cuadro de diálogo simple o lo que sea que devuelva super.onCreateDialog. Esta es la solución que he encontrado que funciona mejor.
Advertencia: Otros cuadros de diálogo como DatePickerDialog, ProgressDialog, TimePickerDialog todos heredan de AlertDialog y probablemente causen el mismo error.
Conclusión: DialogFragment es bueno si necesita crear una interfaz muy personalizada que necesite ser utilizada en varios lugares. No parece funcionar para reutilizar los diálogos de Android existentes.
No he inflado de XML, pero he hecho la generación de vista dinámica en un DialogFragment con éxito:
@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();
}
Yo tuve el mismo problema. En mi caso, fue porque Android Studio creó una plantilla en CreateView que volvió a inflar una nueva vista en lugar de devolver la vista creada en onCreateDialog. Se llama a onCreateView después de onCreateDialog, por lo que la solución fue simplemente volver a generar la vista de fragmentos.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return this.getView();
}