Position de DialogFragment dans Android
-
13-12-2019 - |
Question
j'ai un DialogFragment
montrer un View
comme un écran contextuel.La fenêtre apparaît toujours au milieu de l'écran.Existe-t-il un moyen de définir la position du DialogFragment
fenêtre?J'ai regardé dans le code source mais je n'ai encore rien trouvé.
La solution
Essayez quelque chose comme ceci :
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
getDialog().getWindow().setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
WindowManager.LayoutParams p = getDialog().getWindow().getAttributes();
p.width = ViewGroup.LayoutParams.MATCH_PARENT;
p.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE;
p.x = 200;
...
getDialog().getWindow().setAttributes(p);
...
ou d'autres méthodes pour getDialog().getWindow()
.
assurez-vous de définir la position après avoir appelé set-content.
Autres conseils
C'est vrai, je me suis cogné la tête contre le mur pendant une heure ou deux avec ça, avant de finalement obtenir DialogFragment
positionné comme je le voulais.
je bâtis sur La réponse de Steelight ici.C'est l'approche la plus simple et la plus fiable que j'ai trouvée.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle b) {
Window window = getDialog().getWindow();
// set "origin" to top left corner, so to speak
window.setGravity(Gravity.TOP|Gravity.LEFT);
// after that, setting values for x and y works "naturally"
WindowManager.LayoutParams params = window.getAttributes();
params.x = 300;
params.y = 100;
window.setAttributes(params);
Log.d(TAG, String.format("Positioning DialogFragment to: x %d; y %d", params.x, params.y));
}
Noter que params.width
et params.softInputMode
(utilisés dans la réponse de Steelight) ne sont pas pertinents pour cela.
Vous trouverez ci-dessous un exemple plus complet.Ce dont j'avais vraiment besoin, c'était d'aligner un DialogFragment "boîte de confirmation" à côté d'une vue "source" ou "parente", dans mon cas, un ImageButton.
J'ai choisi d'utiliser DialogFragment, au lieu de n'importe quel Fragment personnalisé, car il vous offre gratuitement des fonctionnalités de "dialogue" (fermer la boîte de dialogue lorsque l'utilisateur clique à l'extérieur, etc.).
Exemple ConfirmBox au-dessus de son ImageButton "source" (poubelle)
/**
* A custom DialogFragment that is positioned above given "source" component.
*
* @author Jonik, https://stackoverflow.com/a/20419231/56285
*/
public class ConfirmBox extends DialogFragment {
private View source;
public ConfirmBox() {
}
public ConfirmBox(View source) {
this.source = source;
}
public static ConfirmBox newInstance(View source) {
return new ConfirmBox(source);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(STYLE_NO_FRAME, R.style.Dialog);
}
@Override
public void onStart() {
super.onStart();
// Less dimmed background; see https://stackoverflow.com/q/13822842/56285
Window window = getDialog().getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.dimAmount = 0.2f; // dim only a little bit
window.setAttributes(params);
// Transparent background; see https://stackoverflow.com/q/15007272/56285
// (Needed to make dialog's alpha shadow look good)
window.setBackgroundDrawableResource(android.R.color.transparent);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Put your dialog layout in R.layout.view_confirm_box
View view = inflater.inflate(R.layout.view_confirm_box, container, false);
// Initialise what you need; set e.g. button texts and listeners, etc.
// ...
setDialogPosition();
return view;
}
/**
* Try to position this dialog next to "source" view
*/
private void setDialogPosition() {
if (source == null) {
return; // Leave the dialog in default position
}
// Find out location of source component on screen
// see https://stackoverflow.com/a/6798093/56285
int[] location = new int[2];
source.getLocationOnScreen(location);
int sourceX = location[0];
int sourceY = location[1];
Window window = getDialog().getWindow();
// set "origin" to top left corner
window.setGravity(Gravity.TOP|Gravity.LEFT);
WindowManager.LayoutParams params = window.getAttributes();
// Just an example; edit to suit your needs.
params.x = sourceX - dpToPx(110); // about half of confirm button size left of source view
params.y = sourceY - dpToPx(80); // above source view
window.setAttributes(params);
}
public int dpToPx(float valueInDp) {
DisplayMetrics metrics = getActivity().getResources().getDisplayMetrics();
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
}
Il est assez facile de rendre l'utilisation ci-dessus plus générale en ajoutant des paramètres de constructeur ou des setters si nécessaire.(Ma finale ConfirmBox
a un bouton stylisé (à l'intérieur de certaines bordures, etc.) dont le texte et View.OnClickListener
peut être personnalisé dans le code.)
getDialog().getWindow()
ne fonctionnera pas pour un DialogFragment
comme getWindow()
renverra null si l'activité d'hébergement n'est pas visible, ce qui n'est pas le cas si vous écrivez une application basée sur des fragments.Vous obtiendrez un NullPointerException
quand tu essaies getAttributes()
.
Je recommande la réponse de Mobistry.Si vous disposez déjà d’une classe DialogFragment, il n’est pas trop difficile d’en changer.Remplacez simplement la méthode onCreateDialog par une méthode qui construit et renvoie une PopupWindow.Vous devriez alors pouvoir réutiliser la vue que vous fournissez AlertDialog.builder.setView()
, et appelle (PopupWindow object).showAtLocation()
.
Vous devez remplacer la méthode onResume() dans votre DialogFragment comme suit :
@Override
public void onResume() {
final Window dialogWindow = getDialog().getWindow();
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
lp.x = 100; // set your X position here
lp.y = 200; // set your Y position here
dialogWindow.setAttributes(lp);
super.onResume();
}
J'utilise la classe PopupWindow à cet effet car vous pouvez spécifier l'emplacement et la taille de la vue.
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = new Dialog(mActivity, R.style.BottomDialog);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); //
dialog.setContentView(R.layout.layout_video_live);
dialog.setCanceledOnTouchOutside(true);
Window window = dialog.getWindow();
assert window != null;
WindowManager.LayoutParams lp = window.getAttributes();
lp.gravity = Gravity.BOTTOM; //psotion
lp.width = WindowManager.LayoutParams.MATCH_PARENT; // fuill screen
lp.height = 280;
window.setAttributes(lp);
return dialog;
}
j'utilise AppCompatDialogFragment
depuis android.support.v7.app.AppCompatDialogFragment
et je souhaite aligner le fragment de boîte de dialogue au bas de l'écran et également supprimer toutes les bordures, en particulier je devais définir la largeur du contenu pour qu'elle corresponde au parent.
Donc, je voulais de ceci (le fond jaune vient du rootLayout du fragment de dialogue) :
Obtenez ceci :
Aucune des solutions ci-dessus n'a fonctionné.J'ai donc réussi à faire ceci :
fun AppCompatDialogFragment.alignToBottom() {
dialog.window.apply {
setGravity(Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
decorView.apply {
// Get screen width
val displayMetrics = DisplayMetrics().apply {
windowManager.defaultDisplay.getMetrics(this)
}
setBackgroundColor(Color.WHITE) // I don't know why it is required, without it background of rootView is ignored (is transparent even if set in xml/runtime)
minimumWidth = displayMetrics.widthPixels
setPadding(0, 0, 0, 0)
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
invalidate()
}
}
}