hacer - tipos de dialogos en android studio
¿Cómo establecer el ancho y alto de DialogFragment? (21)
Especifico el diseño de mi DialogFragment en un archivo de diseño xml (llamémoslo layout_mydialogfragment.xml
), y sus layout_width
y layout_height
particularmente (para ser 100dp
cada uno digamos). A continuación, infló este diseño en mi método onCreateView(...)
siguiente manera:
View view = inflater.inflate(R.layout.layout_mydialogfragment, container, false);
Lamentablemente, me parece que cuando aparece mi cuadro de diálogo (DialogFragment), no respeta el layout_width
y el layout_height
especificados en su archivo de diseño xml (y mi diálogo se reduce o se expande de forma variable según el contenido). ¿Alguien sabe si puedo hacer que mi diálogo respete el layout_width
y el layout_height
especificados en su archivo de diseño xml? Por el momento, tengo que especificar el ancho y alto de mi diálogo nuevamente en el método onResume()
siguiente manera ...
getDialog().getWindow().setLayout(width, height);
... Y, por lo tanto, de forma no deseable, debe recordar realizar cualquier cambio futuro en el ancho y alto del diálogo en dos lugares.
Gotcha # 13: DialogFragment
Layouts
Es una especie de entumecimiento de la mente realmente.
Al crear un DialogFragment
, puede optar por anular onCreateView
(que pasa un ViewGroup
para adjuntar su diseño .xml) o onCreateDialog
, que no lo hace.
No debes anular ambos métodos, ¡porque es muy probable que confundas a Android con respecto a cuándo y cuándo se infló el diseño de tu diálogo! WTF?
La opción de anular OnCreateDialog
o OnCreateView
depende de cómo pretenda usar el diálogo.
- Si inicia el diálogo en una ventana (el comportamiento normal), se espera que anule
OnCreateDialog
. - Si tiene la intención de incrustar el fragmento de diálogo dentro de un diseño de interfaz de usuario existente (FAR es menos común), se espera que anule
OnCreateView
.
Esto es posiblemente lo peor del mundo.
onCreateDialog
Locura
Por lo tanto, está redefiniendo onCreateDialog
en su DialogFragment
para crear una instancia personalizada de AlertDialog
que se mostrará en una ventana. Guay. Pero recuerde, onCreateDialog
no recibe ViewGroup
para adjuntar su diseño .xml personalizado. No hay problema, simplemente pasa null
al método inflate
.
Que comience la locura.
Cuando sobrescribe en onCreateDialog
, Android IGNORA COMPLETAMENTE varios atributos del nodo raíz del .xml Layout que infle. Esto incluye, pero probablemente no se limite a:
-
background_color
-
layout_gravity
-
layout_width
-
layout_height
Esto es casi cómico, ya que se requiere que establezca el
layout_width
y ellayout_height
de CADA .xml Layout o Android Studio le dará una pequeña insignia roja de vergüenza.
Solo la palabra DialogFragment
me da ganas de vomitar. Podría escribir una novela llena de trampas y errores de Android, pero esta es una de las más intrépidas.
Para volver a la sensatez, primero, declaramos un estilo para restaurar SOLO el background_color
y el layout_gravity
que esperamos:
<style name="MyAlertDialog" parent="Theme.AppCompat.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:layout_gravity">center</item>
</style>
El estilo anterior hereda del tema base para Diálogos (en el tema de AppCompat
en este ejemplo).
A continuación, aplicamos el estilo mediante programación para recuperar los valores que acaba de abandonar Android y restaurar el aspecto y la sensación estándar de AlertDialog
:
public class MyDialog extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View layout = getActivity().getLayoutInflater().inflate(R.layout.my_dialog_layout, null, false);
assert layout != null;
//build the alert dialog child of this fragment
AlertDialog.Builder b = new AlertDialog.Builder(getActivity());
//restore the background_color and layout_gravity that Android strips
b.getContext().getTheme().applyStyle(R.style.MyAlertDialog, true);
b.setView(layout);
return b.create();
}
}
El código anterior hará que su AlertDialog
parecerse a AlertDialog
. Tal vez esto es lo suficientemente bueno.
¡Pero espera hay mas!
Si está buscando establecer un layout_width
o layout_height
para su AlertDialog
cuando se muestre (muy probablemente), entonces adivine qué, ¡aún no ha terminado!
La hilaridad continúa cuando te das cuenta de que si intentas establecer un layout_width
o un layout_width
específicos en tu nuevo y elegante estilo, Android también lo ignorará por completo:
<style name="MyAlertDialog" parent="Theme.AppCompat.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:layout_gravity">center</item>
<!-- NOPE!!!!! --->
<item name="android:layout_width">200dp</item>
<!-- NOPE!!!!! --->
<item name="android:layout_height">200dp</item>
</style>
Para establecer un ancho o alto de ventana ESPECÍFICO, puede dirigirse a un método completo y tratar con LayoutParams
:
@Override
public void onResume() {
super.onResume();
Window window = getDialog().getWindow();
if(window == null) return;
WindowManager.LayoutParams params = window.getAttributes();
params.width = 400;
params.height = 400;
window.setAttributes(params);
}
Muchas personas siguen el mal ejemplo de Android de lanzar
WindowManager.LayoutParams
hasta elViewGroup.LayoutParams
más general, solo para girar a la derecha y lanzarViewGroup.LayoutParams
nuevo aWindowManager.LayoutParams
unas líneas más adelante. El Java efectivo no puede ser condenado, el casting innecesario no ofrece NADA más que hacer que el código sea aún más difícil de descifrar.Nota al
LayoutParams
: Hay unas VEINTE repeticiones deLayoutParams
en el Android SDK, un ejemplo perfecto de diseño radicalmente pobre.
En resumen
Para DialogFragment
s que anula onCreateDialog
:
- Para restablecer el aspecto y la sensación estándar de
AlertDialog
, cree un estilo que establezcabackground_color
=transparent
ylayout_gravity
=center
y aplique ese estilo enonCreateDialog
. - Para establecer un
layout_width
y / olayout_height
, hágalo mediante programación enonResume
conLayoutParams
- Para mantener la cordura, trata de no pensar en el SDK de Android.
A continuación, puede configurar el ancho y el alto de diseño desde Java.
final AlertDialog alertDialog = alertDialogBuilder.create();
final WindowManager.LayoutParams WMLP = alertDialog.getWindow().getAttributes();
WMLP.gravity = Gravity.TOP;
WMLP.y = mActionBarHeight;
WMLP.x = getResources().getDimensionPixelSize(R.dimen.unknown_image_width);
alertDialog.getWindow().setAttributes(WMLP);
alertDialog.show();
Aquí hay una manera de establecer el ancho / alto de DialogFragment en xml. Simplemente envuelva su viewHierarchy en un Framelayout (cualquier diseño funcionará) con un fondo transparente.
Un fondo transparente parece ser una bandera especial, ya que centra automáticamente el elemento secundario de frameLayout en la ventana cuando haces eso. Todavía obtendrá el oscurecimiento de la pantalla completa detrás de su fragmento, indicando que su fragmento es el elemento activo.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/transparent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="@color/background_material_light">
.....
Creo el diálogo usando AlertDialog.Builder, así que usé la respuesta de Rodrigo dentro de OnShowListener.
dialog.setOnShowListener(new OnShowListener() {
@Override
public void onShow(DialogInterface dialogInterface) {
Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics ();
display.getMetrics(outMetrics);
dialog.getWindow().setLayout((int)(312 * outMetrics.density), (int)(436 * outMetrics.density));
}
});
Cuando necesito hacer que DialogFragment sea un poco más ancho, estoy configurando minWidth:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="320dp"
... />
En mi caso fue causado por align_parentBottom="true"
dado a una vista dentro de RelativeLayout
. Se eliminaron todos los alignParentBottom y se cambiaron todos los diseños a LinearLayouts verticales y el problema desapareció.
Establezca el diseño principal del diseño de diálogo personalizado en RelativeLayout , obtenga ancho y alto comunes automáticamente.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
Fácil y sólido:
@Override
public void onResume() {
// Sets the height and the width of the DialogFragment
int width = ConstraintLayout.LayoutParams.MATCH_PARENT;
int height = ConstraintLayout.LayoutParams.MATCH_PARENT;
getDialog().getWindow().setLayout(width, height);
super.onResume();
}
La dimensión en el diseño más externo no funciona en el diálogo. Puede agregar un diseño donde establecer la dimensión debajo de la más externa.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="xxdp"
android:layout_height="xxdp"
android:orientation="vertical">
</LinearLayout>
Lo único que funcionó en mi caso fue la solución apuntada aquí: http://adilatwork.blogspot.mx/2012/11/android-dialogfragment-dialog-sizing.html
Fragmento de la publicación de blog de Adil:
@Override
public void onStart()
{
super.onStart();
// safety check
if (getDialog() == null)
return;
int dialogWidth = ... // specify a value here
int dialogHeight = ... // specify a value here
getDialog().getWindow().setLayout(dialogWidth, dialogHeight);
// ... other stuff you want to do in your onStart() method
}
Lo arreglé estableciendo los parámetros de diseño del elemento raíz.
int width = activity.getResources().getDisplayMetrics().widthPixels;
int height = activity.getResources().getDisplayMetrics().heightPixels;
content.setLayoutParams(new LinearLayout.LayoutParams(width, height));
Obtuve un DialogFragment de tamaño fijo que define lo siguiente en el diseño principal de XML (LinearLayout en mi caso):
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="1000dp"
android:minHeight="450dp"
Para obtener un cuadro de diálogo que cubra casi todo el pedregal: primero defina una clase ScreenParameter
public class ScreenParameters
{
public static int Width;
public static int Height;
public ScreenParameters()
{
LayoutParams l = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
Width= l.width;
Height = l.height;
}
}
Luego debe llamar al ScreenParamater antes de su método getDialog.getWindow (). SetLayout ()
@Override
public void onResume()
{
super.onResume();
ScreenParameters s = new ScreenParameters();
getDialog().getWindow().setLayout(s.Width , s.Height);
}
Puede usar porcentajes para el ancho.
<style name="Theme.Holo.Dialog.MinWidth">
<item name="android:windowMinWidthMajor">70%</item>
Usé Holo Theme para este ejemplo.
Sé que esto es antiguo, pero la solución más limpia que he encontrado es anular en onCreateDialog()
lugar de onCreateView()
. Lo que hace que mi respuesta sea diferente es cómo configuro la vista y devuelvo el diálogo. Elimina la necesidad de almacenar / establecer una dimensión, color de fondo, estilo, etc.
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = new Dialog(getActivity());
dialog.setContentView(R.layout.fragment_dialog);
Button button = (Button) dialog.findViewById(R.id.dialog_button);
// ...
return dialog;
}
Si convierte directamente desde valores de recursos:
int width = getResources().getDimensionPixelSize(R.dimen.popup_width);
int height = getResources().getDimensionPixelSize(R.dimen.popup_height);
getDialog().getWindow().setLayout(width, height);
Luego, especifique match_parent en su diseño para el diálogo:
android:layout_width="match_parent"
android:layout_height="match_parent"
Solo debe preocuparse por un lugar (colóquelo en su DialogFragment#onResume
). No es perfecto, pero al menos funciona para tener un RelativeLayout como la raíz del archivo de diseño de su diálogo.
Terminé reemplazando a Fragment.onResume()
y tomando los atributos del cuadro de diálogo subyacente, luego establecí los parámetros ancho / alto allí. Configuro la altura / ancho del diseño más externo para match_parent
. Tenga en cuenta que este código parece respetar también los márgenes que definí en el diseño xml.
@Override
public void onResume() {
super.onResume();
ViewGroup.LayoutParams params = getDialog().getWindow().getAttributes();
params.width = LayoutParams.MATCH_PARENT;
params.height = LayoutParams.MATCH_PARENT;
getDialog().getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
}
Trabajando en Android 6.0, se encontró con el mismo problema. AlertDialog
forma predeterminada el width
predefinido establecido en el tema, independientemente del width
real establecido en el Layout
raíz de la vista personalizada. Pude hacer que se ajustara correctamente ajustando el width
de la TextView
. Sin investigar más, parece que dimensionar los elementos reales y tener el ajuste de Layout
raíz a su alrededor lo hace funcionar como se esperaba. A continuación se muestra un diseño XML de un diálogo de carga que establece el width
del diálogo correctamente. Usando esta biblioteca para la animación.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/custom_color"
android:padding="@dimen/custom_dimen">
<com.github.rahatarmanahmed.cpv.CircularProgressView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/progress_view"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerHorizontal="true"
app:cpv_color="@color/white"
app:cpv_animAutostart="true"
app:cpv_indeterminate="true" />
<TextView
android:id="@+id/loading_message"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_below="@+id/progress_view"
android:layout_centerHorizontal="true"
android:gravity="center"
android:textSize="18dp"
android:layout_marginTop="@dimen/custom_dimen"
android:textColor="@color/white"
android:text="@string/custom_string"/>
</RelativeLayout>
Una de las soluciones anteriores casi funcionó. Intenté algo ligeramente diferente y terminó trabajando para mí.
(Asegúrese de ver su solución) Esta fue su solución. Haga clic aquí Funcionó, excepto para: builder.getContext (). GetTheme (). ApplyStyle (R.style.Theme_Window_NoMinWidth, true);
Lo cambié a
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get layout inflater
LayoutInflater layoutInflater = getActivity().getLayoutInflater();
// Set layout by setting view that is returned from inflating the XML layout
builder.setView(layoutInflater.inflate(R.layout.dialog_window_layout, null));
AlertDialog dialog = builder.create();
dialog.getContext().setTheme(R.style.Theme_Window_NoMinWidth);
La última línea es realmente diferente.
Una forma de controlar el ancho y alto de su DialogFragment
es asegurarse de que su diálogo respeta el ancho y el alto de su vista si su valor es WRAP_CONTENT
.
Usando ThemeOverlay.AppCompat.Dialog
Una forma simple de lograr esto es hacer uso del estilo ThemeOverlay.AppCompat.Dialog
que se incluye en la Biblioteca de soporte de Android.
DialogFragment
con Dialog
:
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(R.layout.dialog_view, null);
Dialog dialog = new Dialog(getContext(), R.style.ThemeOverlay_AppCompat_Dialog);
dialog.setContentView(view);
return dialog;
}
DialogFragment
con AlertDialog
(advertencia: minHeight="48dp"
):
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(R.layout.dialog_view, null);
AlertDialog.Builder builder = new AlertDialog.Builder(getContext(), R.style.ThemeOverlay_AppCompat_Dialog);
builder.setView(view);
return builder.create();
}
También puede establecer ThemeOverlay.AppCompat.Dialog
como el tema predeterminado al crear sus diálogos, agregándolo al tema xml de su aplicación.
Tenga cuidado, ya que muchos diálogos necesitan el ancho mínimo predeterminado para verse bien.
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- For Android Dialog. -->
<item name="android:dialogTheme">@style/ThemeOverlay.AppCompat.Dialog</item>
<!-- For Android AlertDialog. -->
<item name="android:alertDialogTheme">@style/ThemeOverlay.AppCompat.Dialog</item>
<!-- For AppCompat AlertDialog. -->
<item name="alertDialogTheme">@style/ThemeOverlay.AppCompat.Dialog</item>
<!-- Other attributes. -->
</style>
DialogFragment
con Dialog
, haciendo uso de android:dialogTheme
:
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(R.layout.dialog_view, null);
Dialog dialog = new Dialog(getContext());
dialog.setContentView(view);
return dialog;
}
DialogFragment
con AlertDialog
, haciendo uso de android:alertDialogTheme
o alertDialogTheme
(advertencia: minHeight="48dp"
):
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(R.layout.dialog_view, null);
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(view);
return builder.create();
}
Prima
En las API de Android anteriores, los Dialog
parecen tener algunos problemas de ancho, debido a su título (incluso si no establece uno).
Si no desea utilizar el estilo ThemeOverlay.AppCompat.Dialog
y su Dialog
no necesita un título (o tiene uno personalizado), es posible que desee deshabilitarlo:
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(R.layout.dialog_view, null);
Dialog dialog = new Dialog(getContext());
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
return dialog;
}
Respuesta obsoleta, no funcionará en la mayoría de los casos
Intenté que el diálogo respetara el ancho y alto de mi diseño, sin especificar un tamaño fijo programáticamente.
Pensé que android:windowMinWidthMinor
y android:windowMinWidthMajor
estaban causando el problema. A pesar de que no estaban incluidos en el tema de mi Activity
o Dialog
, de alguna manera todavía se estaban aplicando al tema Activity
.
Se me ocurrieron tres posibles soluciones.
Solución 1: cree un tema de diálogo personalizado y DialogFragment
cuando cree el diálogo en DialogFragment
.
<style name="Theme.Material.Light.Dialog.NoMinWidth" parent="android:Theme.Material.Light.Dialog">
<item name="android:windowMinWidthMinor">0dip</item>
<item name="android:windowMinWidthMajor">0dip</item>
</style>
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new Dialog(getActivity(), R.style.Theme_Material_Light_Dialog_NoMinWidth);
}
Solución 2: cree un tema personalizado para usar en ContextThemeWrapper
que servirá como Context
para el diálogo. Úselo si no desea crear un tema de diálogo personalizado (por ejemplo, cuando desea usar el tema especificado por android:dialogTheme
).
<style name="Theme.Window.NoMinWidth" parent="">
<item name="android:windowMinWidthMinor">0dip</item>
<item name="android:windowMinWidthMajor">0dip</item>
</style>
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new Dialog(new ContextThemeWrapper(getActivity(), R.style.Theme_Window_NoMinWidth), getTheme());
}
Solución 3 (con un AlertDialog
): AlertDialog
android:windowMinWidthMinor
y android:windowMinWidthMajor
en ContextThemeWrapper
creado por AlertDialog$Builder
.
<style name="Theme.Window.NoMinWidth" parent="">
<item name="android:windowMinWidthMinor">0dip</item>
<item name="android:windowMinWidthMajor">0dip</item>
</style>
@Override
public final Dialog onCreateDialog(Bundle savedInstanceState) {
View view = new View(); // Inflate your view here.
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(view);
// Make sure the dialog width works as WRAP_CONTENT.
builder.getContext().getTheme().applyStyle(R.style.Theme_Window_NoMinWidth, true);
return builder.create();
}
@Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null)
{
dialog.getWindow().setLayout(-1, -2);
dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
Window window = getDialog().getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.dimAmount = 1.0f;
window.setAttributes(params);
window.setBackgroundDrawableResource(android.R.color.transparent);
}
}