Je spécifie la mise en page de mon DialogFragment dans un fichier de mise en page xml (appelons-le layout_mydialogfragment.xml
), et ses attributs layout_width
et layout_height
particulièrement (à être 100dp
chacun, par exemple). Je gonfle ensuite cette présentation dans la méthode onCreateView(...)
de mon DialogFragment comme suit:
View view = inflater.inflate(R.layout.layout_mydialogfragment, container, false);
Malheureusement, je constate que lorsque ma boîte de dialogue (DialogFragment) apparaît, elle ne respecte pas les layout_width
et layout_height
spécifiés dans son fichier de présentation XML (et ma boîte de dialogue se réduit ou se développe de manière variable en fonction du contenu). Quelqu'un sait si ou comment je peux obtenir que ma boîte de dialogue respecte les layout_width
et layout_height
spécifiés dans son fichier de présentation XML? Pour le moment, je dois spécifier la largeur et la hauteur de ma boîte de dialogue dans la méthode onResume()
de mon DialogFragment comme suit ...
getDialog().getWindow().setLayout(width, height);
... Et ainsi, de façon indésirable, vous devez vous rappeler de modifier à tout moment la largeur et la hauteur de la boîte de dialogue à deux endroits.
Si vous convertissez directement à partir de valeurs de ressources:
int width = getResources().getDimensionPixelSize(R.dimen.popup_width);
int height = getResources().getDimensionPixelSize(R.dimen.popup_height);
getDialog().getWindow().setLayout(width, height);
Puis spécifiez match_parent dans votre présentation pour la boîte de dialogue:
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Vous ne devez vous préoccuper que d’un seul endroit (placez-le dans votre DialogFragment#onResume
). Ce n'est pas parfait, mais au moins cela fonctionne pour avoir un RelativeLayout comme racine du fichier de disposition de votre boîte de dialogue.
J'ai fini par surcharger Fragment.onResume()
et récupérer les attributs dans la boîte de dialogue sous-jacente, puis y définir les paramètres width/height. Je règle la hauteur/largeur de la mise en page la plus externe sur match_parent
. Notez que ce code semble respecter les marges que j'ai définies dans la mise en page 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);
}
J'ai un DialogFragment de taille fixe définissant les éléments suivants dans la présentation principale XML (LinearLayout dans mon cas):
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:minWidth="1000dp"
Android:minHeight="450dp"
La seule chose qui a fonctionné dans mon cas a été la solution indiquée ici: http://adilatwork.blogspot.mx/2012/11/Android-dialogfragment-dialog-sizing.html
Extrait de l'article de blog 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
}
Une façon de contrôler la largeur et la hauteur de votre DialogFragment
consiste à vous assurer que sa boîte de dialogue respecte la largeur et la hauteur de votre vue si leur valeur est WRAP_CONTENT
.
ThemeOverlay.AppCompat.Dialog
Un moyen simple d'y parvenir consiste à utiliser le style ThemeOverlay.AppCompat.Dialog
inclus dans Android Support Library.
DialogFragment
avec 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
avec AlertDialog
(avertissement: 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();
}
Vous pouvez également définir ThemeOverlay.AppCompat.Dialog
comme thème par défaut lors de la création de vos boîtes de dialogue, en l'ajoutant au thème XML de votre application.
Attention, comme beaucoup de boîtes de dialogue ont besoin de la largeur minimale par défaut pour bien paraître.
<!-- 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
avec Dialog
, en utilisant 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
avec AlertDialog
, en utilisant Android:alertDialogTheme
ou alertDialogTheme
(mise en garde: 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();
}
Sur les anciennes API Android, Dialog
s semble avoir quelques problèmes de largeur, en raison de leur titre (même si vous n'en définissez pas un).
Si vous ne voulez pas utiliser le style ThemeOverlay.AppCompat.Dialog
et que votre Dialog
n'a pas besoin d'un titre (ou qu'il en ait un personnalisé), vous pouvez le désactiver:
@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;
}
J'essayais de faire en sorte que le dialogue respecte la largeur et la hauteur de ma mise en page, sans spécifier de taille fixe par programme.
J'ai pensé que Android:windowMinWidthMinor
et Android:windowMinWidthMajor
étaient à l'origine du problème. Même s'ils n'étaient pas inclus dans le thème de ma Activity
ou Dialog
, ils étaient toujours appliqués au thème Activity
, d'une manière ou d'une autre.
J'ai proposé trois solutions possibles.
Solution 1: créez un thème de dialogue personnalisé et utilisez-le pour créer le dialogue dans la variable 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);
}
Solution 2: créez un thème personnalisé à utiliser dans une ContextThemeWrapper
qui servira de Context
pour le dialogue. Utilisez cette option si vous ne souhaitez pas créer un thème de dialogue personnalisé (par exemple, lorsque vous souhaitez utiliser le thème spécifié par 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());
}
Solution 3 (avec une AlertDialog
): applique Android:windowMinWidthMinor
et Android:windowMinWidthMajor
dans la ContextThemeWrapper
créée par le 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();
}
DialogFragment
LayoutsC'est une sorte d'esprit engourdi vraiment.
Lors de la création d'une DialogFragment
, vous pouvez choisir de remplacer onCreateView
(qui passe une ViewGroup
pour attacher votre mise en page .xml) ou onCreateDialog
, ce qui n'est pas le cas.
Vous ne devez pas remplacer les deux méthodes, car vous allez très probablement confondre Android pour savoir quand ou si la disposition de votre dialogue a été gonflée! WTF?
Le choix de remplacer OnCreateDialog
ou OnCreateView
dépend de la manière dont vous envisagez d'utiliser la boîte de dialogue.
OnCreateDialog
.OnCreateView
.C'est peut-être la pire chose au monde.
onCreateDialog
folieDonc, vous substituez onCreateDialog
dans votre DialogFragment
pour créer une instance personnalisée de AlertDialog
à afficher dans une fenêtre. Cool. Mais rappelez-vous, onCreateDialog
ne reçoit pas ViewGroup
pour attacher votre mise en page .xml personnalisée à. Aucun problème, vous passez simplement null
à la méthode inflate
.
Que la folie commence.
Lorsque vous remplacez onCreateDialog
, Android COMPLÈTEMENT IGNORES plusieurs attributs du nœud racine de la présentation .xml à gonfler. Cela inclut, mais n'est probablement pas limité à:
background_color
layout_gravity
layout_width
layout_height
C'est presque comique, car vous devez définir les
layout_width
etlayout_height
de TOUTES les .Xml Layout ou Android Studio vous gifleront avec un joli petit badge rouge de honte.
Juste le WordDialogFragment
me donne envie de vomir. Je pourrais écrire un roman rempli de pièges Android et de snafus, mais celui-ci est l'un des plus internes.
Pour revenir à la raison, d’abord, nous déclarons un style pour restaurer JUST le background_color
et le layout_gravity
que nous attendons:
<style name="MyAlertDialog" parent="Theme.AppCompat.Dialog">
<item name="Android:windowBackground">@Android:color/transparent</item>
<item name="Android:layout_gravity">center</item>
</style>
Le style ci-dessus hérite du thème de base des dialogues (dans le thème AppCompat
dans cet exemple).
Ensuite, nous appliquons le style par programme pour rétablir les valeurs que Android vient de mettre de côté et pour restaurer l'aspect et la convivialité standard 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();
}
}
Le code ci-dessus fera à nouveau votre AlertDialog
ressembler à une AlertDialog
. Peut-être que c'est assez bon.
Si vous souhaitez définir unSP&EACUTE;CIFIQUElayout_width
ou layout_height
pour votre AlertDialog
quand il est affiché (très probablement), alors devinez quoi, vous n'avez pas encore terminé!
L'hilarité continue lorsque vous réalisez que si vous essayez de définir un layout_width
ou layout_height
spécifique dans votre nouveau style, Android l'ignorera complètement !:
<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>
Pour définir une largeur ou une hauteur SPÉCIFIQUE dans une fenêtre, vous devez passer à une méthode complète et définir 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);
}
Beaucoup de gens suivent le mauvais exemple d'Android qui transforme
WindowManager.LayoutParams
jusqu'auViewGroup.LayoutParams
plus général, puis tourne à droite et redonneViewGroup.LayoutParams
àWindowManager.LayoutParams
quelques lignes plus tard. À partir de Java, ce casting inutile n’offre rien d’autre que de rendre le code encore plus difficile à déchiffrer.Remarque secondaire: Il existe quelques VINGT répétitions de
LayoutParams
dans le SDK Android - un exemple parfait de conception radicalement médiocre.
Pour DialogFragment
s qui annulent onCreateDialog
:
AlertDialog
, créez un style définissant background_color
= transparent
et layout_gravity
= center
et appliquez ce style dans onCreateDialog
.layout_width
et/ou layout_height
spécifique, faites-le par programme dans onResume
avec LayoutParams
Lorsque j'ai besoin d'élargir un peu plus DialogFragment, je règle minWidth:
<LinearLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:minWidth="320dp"
... />
La dimension dans la mise en page la plus externe ne fonctionne pas dans la boîte de dialogue. Vous pouvez ajouter une mise en page dans laquelle définir la dimension sous la partie la plus externe.
<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>
Je l'ai corrigé en fixant les paramètres de disposition de l'élément racine.
int width = activity.getResources().getDisplayMetrics().widthPixels;
int height = activity.getResources().getDisplayMetrics().heightPixels;
content.setLayoutParams(new LinearLayout.LayoutParams(width, height));
Voici un moyen de définir la largeur/hauteur de DialogFragment en xml. Enveloppez simplement votre hiérarchie viewHenram dans un Framelayout (toute mise en page fonctionnera) avec un fond transparent.
Un arrière-plan transparent semble être un indicateur spécial, car il centre automatiquement l'enfant de frameLayout dans la fenêtre. Vous obtiendrez toujours le noircissement complet de l’écran derrière votre fragment, indiquant que votre fragment est l’élément actif.
<?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">
.....
Vous pouvez utiliser un pourcentage pour la largeur.
<style name="Theme.Holo.Dialog.MinWidth">
<item name="Android:windowMinWidthMajor">70%</item>
J'ai utilisé Holo Theme pour cet exemple.
Vous pouvez utiliser le code ci-dessous pour définir la largeur et la hauteur de la présentation à partir de 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();
Je crée le dialogue en utilisant AlertDialog.Builder, j'ai donc utilisé la réponse de Rodrigo dans un 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));
}
});
Travailler sur Android 6.0, a rencontré le même problème. AlertDialog
serait par défaut à width
prédéfini défini dans le thème, quelle que soit la width
réelle définie dans la racine Layout
de la vue personnalisée. J'ai pu le configurer correctement en ajustant la width
du loading_message
TextView
. Sans plus d’investigation, il semble que le dimensionnement des éléments réels et l’enveloppement de la racine Layout
leur permettent de fonctionner comme prévu. Vous trouverez ci-dessous une présentation XML d'une boîte de dialogue de chargement définissant correctement la variable width
de la boîte de dialogue. Utilisation du cette bibliothèque pour l’animation.
<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>
Je ne vois aucune raison impérieuse de remplacer onResume
ou onStart
pour définir la largeur et la hauteur de Window
dans DialogFragment
's Dialog
- ces méthodes de cycle de vie particulières peuvent être appelées à plusieurs reprises et exécuter inutilement ce code de redimensionnement plusieurs fois changer, mettre en arrière-plan puis mettre en avant l'application, etc. Les conséquences de cette répétition sont assez triviales, mais pourquoi se contenter de cela?
Définir la largeur/hauteur à la place d'une méthode onActivityCreated()
surchargée constituera une amélioration car cette méthode n'est appelée de manière réaliste qu'une seule fois par instance de votre DialogFragment
. Par exemple:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Window window = getDialog().getWindow();
assert window != null;
WindowManager.LayoutParams layoutParams = window.getAttributes();
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
window.setAttributes(layoutParams);
}
Ci-dessus, je viens de définir la largeur à match_parent
quelle que soit l'orientation du périphérique. Si vous souhaitez que la boîte de dialogue Paysage ne soit pas aussi large, vous pouvez vérifier au préalable si getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT
.
Définissez la disposition parente de la présentation personnalisée dans RelativeLayout , obtenir automatiquement la largeur et la hauteur communes.
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
Facile et solide:
@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 meilleure solution que j'ai trouvée consiste à remplacer onCreateDialog()
au lieu de onCreateView()
. setContentView () définira les dimensions correctes de la fenêtre avant de gonfler. Cela évite de stocker/définir une dimension, une couleur d'arrière-plan, un style, etc. dans des fichiers de ressources et de les définir manuellement.
@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;
}
Dans mon cas, cela a été causé par align_parentBottom="true"
donné à une vue à l'intérieur d'une RelativeLayout
. Suppression de tous les alignParentBottom et modification de toutes les dispositions en LinearLayouts vertical et problème résolu.
Ajoutez à votre FragmentDialog
:
public void onResume() {
Window window = getDialog().getWindow();
Point size = new Point();
Display display = window.getWindowManager().getDefaultDisplay();
display.getSize(size);
window.setLayout( (int)(size.x * 0.9), WindowManager.LayoutParams.WRAP_CONTENT );
window.setGravity( Gravity.CENTER );
super.onResume();
}
@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);
}
}
L'une des solutions précédentes a presque fonctionné. J'ai essayé quelque chose de légèrement différent et ça a fini par marcher pour moi.
(Assurez-vous de regarder sa solution) C’était sa solution .. Cliquez ici Cela fonctionnait sauf pour: builder.getContext (). GetTheme (). ApplyStyle (R.style.Theme_Window_NoMinWidth, vrai);
Je l'ai changé pour
@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 dernière ligne est vraiment différente.