web-dev-qa-db-fra.com

Position de DialogFragment dans Android

J'ai un DialogFragment pour montrer un View comme un écran Popup. La fenêtre apparaît toujours au milieu de l'écran. Existe-t-il un moyen de définir la position de la fenêtre DialogFragment? J'ai regardé dans le code source mais je n'ai encore rien trouvé.

58
alfacan

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.

93
Steelight

À droite, je me suis cogné la tête contre le mur pendant une heure ou deux avec ça, avant de finalement mettre DialogFragment positionné comme je le voulais.

Je m'appuie sur 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));
} 

Notez que params.width et params.softInputMode (utilisé dans la réponse de Steelight) n'est pas pertinent pour cela.


Voici un exemple plus complet. Ce dont j'avais vraiment besoin était d'aligner un DialogFragment de "boîte de confirmation" à côté d'une vue "source" ou "parent", dans mon cas un ImageButton.

J'ai choisi d'utiliser DialogFragment, au lieu de tout fragment personnalisé, car il vous offre gratuitement des fonctionnalités de "dialogue" (fermer la boîte de dialogue lorsque l'utilisateur clique en dehors de celui-ci, etc.).

Example ConfirmBox
Exemple ConfirmBox au-dessus de sa "source" ImageButton (corbeille)

/**
 * 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. (Mon dernier ConfirmBox a un bouton stylisé (à l'intérieur de certaines bordures, etc.) dont le texte et View.OnClickListener peut être personnalisé dans le code.)

79
Jonik

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();
}
4

getDialog().getWindow() ne fonctionnera pas pour un DialogFragment car getWindow() renverra null si l'activité d'hébergement n'est pas visible, ce qui n'est pas le cas si vous écrivez un fragment- application basée. Vous obtiendrez un NullPointerException lorsque vous essayez getAttributes().

Je recommande la réponse de Mobistry. Si vous avez déjà une classe DialogFragment, il n'est pas trop difficile de basculer. Remplacez simplement la méthode onCreateDialog par une méthode qui construit et renvoie un PopupWindow. Vous devriez alors être en mesure de réutiliser la vue que vous fournissez à AlertDialog.builder.setView(), et d'appeler (PopupWindow object).showAtLocation().

4
Austin B

J'utilise la classe PopupWindow à cet effet, car vous pouvez spécifier l'emplacement et la taille de la vue.

3
Sileria

J'utilise AppCompatDialogFragment de Android.support.v7.app.AppCompatDialogFragment et je souhaite aligner le fragment de boîte de dialogue en bas de l'écran et également supprimer toutes les bordures, en particulier j'avais besoin de définir la largeur du contenu pour qu'elle corresponde au parent.

Donc, je voulais de cela (le fond jaune vient de rootLayout du fragment de dialogue):

src_img_1

Obtenez ceci:

src_img_2

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()
        }
    }
}
1
Cililing
@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;
}
1
Ven Ren