web-dev-qa-db-fra.com

Flou ou atténuation de l'arrière-plan lorsque Android PopupWindow est activé

J'aimerais pouvoir flouter ou atténuer l'arrière-plan lorsque je montre ma fenêtre contextuelle à l'aide de popup.showAtLocation et dégager/atténuer l'arrière-plan lorsque popup.dismiss est appelé.

J'ai essayé d'appliquer les paramètres de mise en page FLAG_BLUR_BEHIND et FLAG_DIM_BEHIND à mon activité, mais cela semble simplement ternir et assombrir l'arrière-plan dès que mon application est lancée.

Comment puis-je faire du flou/assombrissement juste avec des popups?

72
k_day

La question portait sur la classe Popupwindow, mais tout le monde a donné des réponses qui utilisent la classe Dialog. C’est à peu près inutile si vous devez utiliser la classe Popupwindow, car Popupwindow n’a pas de méthode getWindow().

J'ai trouvé une solution qui fonctionne réellement avec Popupwindow. Il suffit que la racine du fichier XML que vous utilisez pour l'activité en arrière-plan soit une FrameLayout. Vous pouvez attribuer une balise Android:foreground à l'élément Framelayout. Cette balise spécifie une ressource pouvant être dessinée qui sera superposée à toute l'activité (c'est-à-dire si Framelayout est l'élément racine du fichier xml). Vous pouvez alors contrôler l'opacité (setAlpha()) du dessin au premier plan.

Vous pouvez utiliser n’importe quelle ressource pouvant être dessinée, mais si vous souhaitez simplement un effet de gradation, créez un fichier xml dans le dossier pouvant être dessiné avec la balise <shape> en tant que racine.

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:shape="rectangle" >
    <solid Android:color="#000000" />
</shape>

(Voir http://developer.Android.com/guide/topics/resources/drawable-resource.html#Shape pour plus d'informations sur l'élément shape) . Notez que je n'ai pas spécifié d'alpha valeur dans la balise de couleur qui rendrait l’élément dessinable transparent (par exemple, #ff000000). La raison en est que toute valeur alpha codée en dur semble remplacer toute nouvelle valeur alpha définie via la fonction setAlpha() dans notre code, nous ne voulons donc pas que . Cependant, cela signifie que l'élément pouvant être dessiné sera initialement opaque ( solide, non transparent). Nous devons donc le rendre transparent dans la méthode onCreate() de l'activité.

Voici le code de l'élément xml Framelayout:

<FrameLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/mainmenu"
    Android:layout_width="fill_parent"
    Android:layout_height="fill_parent"
    Android:foreground="@drawable/shape_window_dim" >
...
... your activity's content
...
</FrameLayout>

Voici la méthode onCreate () de l'activité:

public void onCreate( Bundle savedInstanceState)
{
  super.onCreate( savedInstanceState);

  setContentView( R.layout.activity_mainmenu);

  //
  // Your own Activity initialization code
  //

  layout_MainMenu = (FrameLayout) findViewById( R.id.mainmenu);
  layout_MainMenu.getForeground().setAlpha( 0);
}

Enfin, le code pour assombrir l’activité:

layout_MainMenu.getForeground().setAlpha( 220); // dim

layout_MainMenu.getForeground().setAlpha( 0); // restore

Les valeurs alpha vont de 0 (opaque) à 255 (invisible) . Vous devez affiner l'activité de l'activité lorsque vous fermez la fenêtre contextuelle.

Je n'ai pas inclus de code pour afficher et ignorer Popupwindow, mais voici un lien vers la procédure à suivre: http://www.mobilemancer.com/2011/01/08/popup-window-in-Android/

99
uhmdown

Puisque PopupWindow ajoute simplement une View à WindowManager, vous pouvez utiliser updateViewLayout (View view, ViewGroup.LayoutParams params) pour mettre à jour la LayoutParams de votre PopupWindow's contentView après avoir appelé show .. (). 

La définition de l’indicateur de fenêtre FLAG_DIM_BEHIND atténuera tout ce qui se trouve derrière la fenêtre. Utilisez dimAmount pour contrôler la quantité de dim (1,0 pour complètement opaque à 0,0 pour sans dim).

N'oubliez pas que si vous définissez un arrière-plan sur votre PopupWindow, il mettra votre contentView dans un conteneur, ce qui signifie que vous devez mettre à jour son parent. 

Avec fond:

PopupWindow popup = new PopupWindow(contentView, width, height);
popup.setBackgroundDrawable(background);
popup.showAsDropDown(anchor);

View container = (View) popup.getContentView().getParent();
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams p = (WindowManager.LayoutParams) container.getLayoutParams();
// add flag
p.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
p.dimAmount = 0.3f;
wm.updateViewLayout(container, p);

Sans fond:

PopupWindow popup = new PopupWindow(contentView, width, height);
popup.setBackgroundDrawable(null);
popup.showAsDropDown(anchor);

WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams p = (WindowManager.LayoutParams) contentView.getLayoutParams();
// add flag
p.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
p.dimAmount = 0.3f;
wm.updateViewLayout(contentView, p);

Mise à jour de guimauve:

Sur M, PopupWindow enveloppe ContentView dans un FrameLayout appelé mDecorView. Si vous creusez dans la source PopupWindow, vous trouverez quelque chose comme createDecorView(View contentView). L'objectif principal de mDecorView est de gérer la transmission d'événements et les transitions de contenu, qui sont nouvelles pour M. Cela signifie que nous devons ajouter un .getParent () supplémentaire pour accéder au conteneur .

Avec un fond qui nécessiterait un changement à quelque chose comme:

View container = (View) popup.getContentView().getParent().getParent();

Meilleure alternative pour API 18+

Une solution moins astucieuse utilisant ViewGroupOverlay:

1) Obtenez la mise en page souhaitée

ViewGroup root = (ViewGroup) getWindow().getDecorView().getRootView();

2) Appelez applyDim(root, 0.5f); ou clearDim()

public static void applyDim(@NonNull ViewGroup parent, float dimAmount){
    Drawable dim = new ColorDrawable(Color.BLACK);
    dim.setBounds(0, 0, parent.getWidth(), parent.getHeight());
    dim.setAlpha((int) (255 * dimAmount));

    ViewGroupOverlay overlay = parent.getOverlay();
    overlay.add(dim);
}

public static void clearDim(@NonNull ViewGroup parent) {
    ViewGroupOverlay overlay = parent.getOverlay();
    overlay.clear();
}
63
Markus Rubey

Dans votre fichier XML, ajoutez quelque chose comme ceci avec la largeur et la hauteur sous la forme "match_parent".

<RelativeLayout
        Android:id="@+id/bac_dim_layout"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:background="#C0000000"
        Android:visibility="gone" >
</RelativeLayout>

Dans votre activité oncreate

//setting background dim when showing popup
back_dim_layout = (RelativeLayout) findViewById(R.id.share_bac_dim_layout);

Enfin, rendez visible lorsque vous affichez votre fenêtre popup et que vous la rendez visible lorsque vous quittez popupwindow.

back_dim_layout.setVisibility(View.VISIBLE);
back_dim_layout.setVisibility(View.GONE);
27
user2257590

Une autre astuce consiste à utiliser 2 fenêtres popup au lieu d'une. La 1ère fenêtre contextuelle sera simplement une vue fictive avec un arrière-plan translucide qui fournit l’effet de dim La 2e fenêtre contextuelle est votre fenêtre contextuelle prévue. 

Séquence lors de la création de fenêtres contextuelles: Affichez la fenêtre contextuelle fictive en premier, puis la fenêtre contextuelle souhaitée.

Séquence lors de la destruction: Fermez la fenêtre contextuelle prévue, puis la fenêtre fictive.

Le meilleur moyen de lier ces deux méthodes est d’ajouter un OnDismissListener et de remplacer la méthode onDismiss() de la fenêtre destinée à réduire la fausse fenêtre contextuelle de leur. 

Code pour la fenêtre fictive:

fadepopup.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:orientation="vertical" 
    Android:id="@+id/fadePopup"
    Android:background="#AA000000">
</LinearLayout>

Afficher le fondu contextuel pour atténuer l'arrière-plan

private PopupWindow dimBackground() {

    LayoutInflater inflater = (LayoutInflater) EPGGRIDActivity.this
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    final View layout = inflater.inflate(R.layout.fadepopup,
            (ViewGroup) findViewById(R.id.fadePopup));
    PopupWindow fadePopup = new PopupWindow(layout, windowWidth, windowHeight, false);
    fadePopup.showAtLocation(layout, Gravity.NO_GRAVITY, 0, 0);
    return fadePopup;
}
11
Abhishek Nandi

J'ai trouvé une solution pour ça

Créez une boîte de dialogue transparente personnalisée et ouvrez la fenêtre contextuelle suivante:

dialog = new Dialog(context, Android.R.style.Theme_Translucent_NoTitleBar);
emptyDialog = LayoutInflater.from(context).inflate(R.layout.empty, null);

/* blur background*/
WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();  
lp.dimAmount=0.0f;  
dialog.getWindow().setAttributes(lp);  
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 
dialog.setContentView(emptyDialog);
dialog.setCanceledOnTouchOutside(true);
dialog.setOnShowListener(new OnShowListener()
{
    @Override
    public void onShow(DialogInterface dialogIx)
    {
        mQuickAction.show(emptyDialog); //open the PopupWindow here
    }
});
dialog.show();

xml pour le dialogue (R.layout.empty):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
     Android:layout_height="match_parent" Android:layout_width="match_parent"
     style="@Android:style/Theme.Translucent.NoTitleBar" />

maintenant, vous voulez fermer la boîte de dialogue lorsque la fenêtre contextuelle est fermée. alors

mQuickAction.setOnDismissListener(new OnDismissListener()
{
    @Override
    public void onDismiss()
    {
        if(dialog!=null)
        {
            dialog.dismiss(); // dismiss the empty dialog when the PopupWindow closes
            dialog = null;
        }
    }
});

Note: J'ai utilisé NewQuickAction plugin pour créer PopupWindow ici. Cela peut aussi être fait sur Popup Windows natif

5
PC.

Vous pouvez utiliser Android:theme="@Android:style/Theme.Dialog" pour le faire . Créez une activité et définissez-la dans votre AndroidManifest.xml comme suit:

    <activity Android:name=".activities.YourActivity"
              Android:label="@string/your_activity_label"
              Android:theme="@Android:style/Theme.Dialog">
0
Macarse

ok, donc je suis (uhmdown) réponse pour atténuer l'activité en arrière-plan lorsque la fenêtre contextuelle est ouverte. Mais cela crée un problème pour moi. il s'agissait d'une activité de gradation et d'inclure une fenêtre contextuelle (signifie également une couche en noir sur l'activité et la fenêtre contextuelle également, il ne peut pas être séparé).

j'ai donc essayé de cette façon,

créer un fichier dimming_black.xml pour un effet d'atténuation,

 <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:shape="rectangle">
    <solid Android:color="#33000000" />
</shape>

Et ajoutez comme background dans FrameLayout en tant que balise xml racine, mettez également mes autres contrôles dans LinearLayout comme ceci layout.xml

<?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:orientation="vertical"
    Android:background="@drawable/ff_drawable_black">

    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:orientation="vertical"
        Android:layout_gravity="bottom"
        Android:background="@color/white">

        // other codes...
    </LinearLayout>

</FrameLayout>

enfin je montre popup sur ma MainActivity avec quelques paramètres supplémentaires comme ci-dessous. 

           //instantiate popup window
            popupWindow = new PopupWindow(viewPopup, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, true);

            //display the popup window
            popupWindow.showAtLocation(layout_ff, Gravity.BOTTOM, 0, 0);

Résultat:enter image description here

cela fonctionne pour moi, également résolu problème commenté par BaDo. Avec cette Actionbar également peut être grisé.

P.s je ne dis pas que uhmdown est faux. J'ai appris sa réponse et essayer d'évoluer pour mon problème. J'ai également confondu si c'est un bon moyen ou non.

Toutes les suggestions sont également appréciées également désolé pour mon mauvais anglais.

0
Sahil M.

Pour moi, quelque chose comme la réponse d'Abdelhak Mouaamou fonctionne, testé sur les niveaux 16 et 27 de l'API.

Au lieu d'utiliser popupWindow.getContentView().getParent() et de convertir le résultat en View (ce qui bloque le niveau 16 de l'API car il renvoie un objet ViewRootImpl qui n'est pas une instance de View). J'utilise simplement .getRootView() qui renvoie déjà une vue.

J'espère que ça aide quelqu'un :)

complétez l'exemple de travail embrouillé à partir d'autres articles de type stackoverflow, copiez-le simplement, par exemple dans l'écouteur onClick d'un bouton:

// inflate the layout of the popup window
LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
if(inflater == null) {
    return;
}
//View popupView = inflater.inflate(R.layout.my_popup_layout, null); // this version gives a warning cause it doesn't like null as argument for the viewRoot, c.f. https://stackoverflow.com/questions/24832497 and https://stackoverflow.com/questions/26404951
View popupView = View.inflate(MyParentActivity.this, R.layout.my_popup_layout, null);

// create the popup window
final PopupWindow popupWindow = new PopupWindow(popupView,
        LinearLayout.LayoutParams.WRAP_CONTENT,
        LinearLayout.LayoutParams.WRAP_CONTENT,
        true // lets taps outside the popup also dismiss it
        );

// do something with the stuff in your popup layout, e.g.:
//((TextView)popupView.findViewById(R.id.textview_popup_helloworld))
//      .setText("hello stackoverflow");

// dismiss the popup window when touched
popupView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            popupWindow.dismiss();
            return true;
        }
});

// show the popup window
// which view you pass in doesn't matter, it is only used for the window token
popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0);
//popupWindow.setOutsideTouchable(false); // doesn't seem to change anything for me

View container = popupWindow.getContentView().getRootView();
if(container != null) {
    WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
    WindowManager.LayoutParams p = (WindowManager.LayoutParams)container.getLayoutParams();
    p.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND;
    p.dimAmount = 0.3f;
    if(wm != null) {
        wm.updateViewLayout(container, p);
    }
}
0
chrisi1698

Peut-être que ce dépôt vous aidera: BasePopup

Ceci est mon repo, qui est utilisé pour résoudre divers problèmes de PopupWindow.

Dans le cas de l'utilisation de la bibliothèque, si vous avez besoin de flouter l'arrière-plan, appelez simplement setBlurBackgroundEnable(true).

Voir le wiki pour plus de détails. (Langue en zh-cn

BasePopup: wiki

0
razerdp