Blur or dim background when Android PopupWindow active
Asked Answered
B

13

92

I would like to be able to either blur or dim the background when I show my popup window using popup.showAtLocation, and unblur/dim the background when popup.dismiss is called.

I have tried applying layout params FLAG_BLUR_BEHIND and FLAG_DIM_BEHIND to my activity, but this appears to just blur and dim the background as soon my app is started.

How can I do blurring/dimming just with popups?

Bailee answered 11/7, 2010 at 1:25 Comment(5)
Word of warning: FLAG_BLUR_BEHIND is buggy on some phones and makes the phone very unresponsive (apparently the blur is done in software). On the Droid, for example. Other than that, what Macarse said - FLAG_BLUR_BEHIND needs to be applied to the window on the foreground.Prevenient
possible duplicate of Best way to show a edit text over screen?Teat
I am looking for the same answer to this question. Is there some way I can programmatically dim the view that isw behind the popupwindow?Venter
@Venter How you solved this problem..Flews
2021 perfect solution: github.com/sergei-lapin/BlurViewBelva
S
113

The question was about the Popupwindow class, yet everybody has given answers that use the Dialog class. Thats pretty much useless if you need to use the Popupwindow class, because Popupwindow doesn't have a getWindow() method.

I've found a solution that actually works with Popupwindow. It only requires that the root of the xml file you use for the background activity is a FrameLayout. You can give the Framelayout element an android:foreground tag. What this tag does is specify a drawable resource that will be layered on top of the entire activity (that is, if the Framelayout is the root element in the xml file). You can then control the opacity (setAlpha()) of the foreground drawable.

You can use any drawable resource you like, but if you just want a dimming effect, create an xml file in the drawable folder with the <shape> tag as root.

<?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>

(See http://developer.android.com/guide/topics/resources/drawable-resource.html#Shape for more info on the shape element). Note that I didn't specify an alpha value in the color tag that would make the drawable item transparent (e.g #ff000000). The reason for this is that any hardcoded alpha value seems to override any new alpha values we set via the setAlpha() in our code, so we don't want that. However, that means that the drawable item will initially be opaque (solid, non-transparent). So we need to make it transparent in the activity's onCreate() method.

Here's the Framelayout xml element code:

<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>

Here's the Activity's onCreate() method:

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

Finally, the code to dim the activity:

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

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

The alpha values go from 0 (opaque) to 255 (invisible). You should un-dim the activity when you dismiss the Popupwindow.

I haven't included code for showing and dismissing the Popupwindow, but here's a link to how it can be done: http://www.mobilemancer.com/2011/01/08/popup-window-in-android/

Siding answered 23/5, 2012 at 17:33 Comment(5)
to ensure that this works on old devices, too you have to invalidate the foreground after every change made to its alpha-channel. I added this to the answer. +1 for the nice answerSelfsown
I cant think of a reason which this isnt marked as the right answer.. awesome answer to say the least.Greenes
What about in view have Actionbar, You cant dim itEisk
this worked best for me...the double popup answer below had a race condition so the dimmed popup sometimes was over the real popupConfiscable
Almost perfect. The only drawback is you have to use FrameLayout since there's no "getForeground" method for other layouts.Polson
S
91

Since PopupWindow just adds a View to WindowManager you can use updateViewLayout (View view, ViewGroup.LayoutParams params) to update the LayoutParams of your PopupWindow's contentView after calling show..().

Setting the window flag FLAG_DIM_BEHIND will dimm everything behind the window. Use dimAmount to control the amount of dim (1.0 for completely opaque to 0.0 for no dim).

Keep in mind that if you set a background to your PopupWindow it will put your contentView into a container, which means you need to update it's parent.

With background:

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);

Without background:

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);

Marshmallow Update:

On M PopupWindow wraps the contentView inside a FrameLayout called mDecorView. If you dig into the PopupWindow source you will find something like createDecorView(View contentView).The main purpose of mDecorView is to handle event dispatch and content transitions, which are new to M. This means we need to add one more .getParent() to access the container.

With background that would require a change to something like:

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

Better alternative for API 18+

A less hacky solution using ViewGroupOverlay:

1) Get a hold of the desired root layout

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

2) Call applyDim(root, 0.5f); or 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();
}
Schermerhorn answered 29/4, 2015 at 17:30 Comment(6)
This no longer seems to work on devices running Android 6.0 Marshmallow. The layoutParams don't cast to WindowManager.LayoutParams. Is there a workaround?Nativity
Thank's for pointing it out. I haven't tested it on M yet. Will update ASAP.Schermerhorn
@ stackoverflow.com/users/308153/robert I also had same issue. I used above code with background.Regeneration
If p is null use this: if (p != null) { //same } else { popupView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { v.removeOnLayoutChangeListener(this); WindowManager.LayoutParams p = (WindowManager.LayoutParams) v.getLayoutParams(); p.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND; p.dimAmount = 0.3f; wm.updateViewLayout(v, p); } }); }Kreis
FYI When I use this on lower API levels (e.g. 15 and 20) it crashes because popup.getContentView().getParent() does not return View so casting it will cause a crash. For this case I used @BeytanKurt's method as the fallback.Regression
@MarkusRubey what i have need to change for the android M , it's crashin of this line () popup.getContentView().getParent().getParent();Tristram
C
30

In your xml file add something like this with width and height as '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>

In your activity oncreate

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

Finally make visible when you show your popupwindow and make its visible gone when you exit popupwindow.

back_dim_layout.setVisibility(View.VISIBLE);
back_dim_layout.setVisibility(View.GONE);
Cracksman answered 8/4, 2013 at 12:40 Comment(3)
but this won't dim the action/tool bar.Gabfest
Plz tell me how to action toolbar dimPadilla
add back_dim_layout.setVisibility(View.GONE); in PopupWindow.OnDismissListenerUntrue
H
12

Another trick is to use 2 popup windows instead of one. The 1st popup window will simply be a dummy view with translucent background which provides the dim effect. The 2nd popup window is your intended popup window.

Sequence while creating pop up windows: Show the dummy pop up window 1st and then the intended popup window.

Sequence while destroying: Dismiss the intended pop up window and then the dummy pop up window.

The best way to link these two is to add an OnDismissListener and override the onDismiss() method of the intended to dimiss the dummy popup window from their.

Code for the dummy popup window:

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>

Show fade popup to dim the background

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;
}
Holotype answered 26/3, 2013 at 7:53 Comment(2)
Almost works for me...sometimes, there's a race condition where the popupwindow is behind the dim/dummy popup window. Haven't found a workaround yet...even delaying the showing of the popupwindow to give it time behind the delayed one doesn't help :-PConfiscable
@Confiscable I've found a fix for this issue. I show 'fade' popup first, and then in order to show second popup I am using myFadePopup.getContentView().post( ... myPopup.showAtLocation ... );Kaylakayle
O
5

I've found a solution for this

Create a custom transparent dialog and inside that dialog open the popup window:

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 for the dialog(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" />

now you want to dismiss the dialog when Popup window dismisses. so

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

Note: I've used NewQuickAction plugin for creating PopupWindow here. It can also be done on native Popup Windows

Obvolute answered 17/2, 2012 at 13:0 Comment(0)
U
1

For me, something like Abdelhak Mouaamou's answer works, tested on API level 16 and 27.

Instead of using popupWindow.getContentView().getParent() and casting the result to View (which crashes on API level 16 cause there it returns a ViewRootImpl object which isn't an instance of View) I just use .getRootView() which returns a view already, so no casting required there.

Hope it helps someone :)

complete working example scrambled together from other stackoverflow posts, just copy-paste it, e.g., in the onClick listener of a button:

// 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);
    }
}
Ultramundane answered 31/1, 2019 at 4:3 Comment(0)
U
1

Maybe this repo will help for you:BasePopup

This is my repo, which is used to solve various problems of PopupWindow.

In the case of using the library, if you need to blur the background, just call setBlurBackgroundEnable(true).

See the wiki for more details.(Language in zh-cn)

BasePopup:wiki

Udelle answered 13/5, 2019 at 1:24 Comment(0)
T
1
findViewById(R.id.drawer_layout).setAlpha((float) 0.7);

R.id.drawer_layout is the id of the layout of which you want to dim the brightness.

Tum answered 6/4, 2020 at 17:22 Comment(0)
R
0

You can use android:theme="@android:style/Theme.Dialog" to do that. Create an activity and in your AndroidManifest.xml define the activity as:

    <activity android:name=".activities.YourActivity"
              android:label="@string/your_activity_label"
              android:theme="@android:style/Theme.Dialog">
Reproductive answered 11/7, 2010 at 1:34 Comment(1)
This doesn't seem to do the trick. I applied to this to my only activity, which is in the background when I show a popup window which is just an inflated layout I have, and not a separate activity. How do I apply FLAG_BLUR_BEHIND to a PopupWindow?Bailee
E
0

ok, so i follow uhmdown's answer for dimming background activity when pop window is open. But it creates problem for me. it was dimming activity and include popup window (means dimmed-black layered on both activity and popup also, it can not be separate them).

so i tried this way,

create an dimming_black.xml file for dimming effect,

 <?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>

And add as background in FrameLayout as root xml tag, also put my other controls in LinearLayout like this 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>

at last i show popup on my MainActivity with some extra parameter set as below.

           //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);

Result: enter image description here

it works for me, also solved problem as commented by BaDo. With this Actionbar also can be dimmed.

P.s i am not saying uhmdown's is wrong. i learnt form his answer and try to evolve for my problem. I also confused whether this is a good way or not.

Any suggestions is also appreciated also sorry for my bad English.

Educe answered 31/12, 2018 at 19:9 Comment(0)
E
0

Since You are trying to pop up your dialog window by blurring the background screen, You must use this set of lines. You need to fetch the dialog attributes first, then set up some alpha values for the dialog attributes.

Now, your dialog with blur background is ready. But the important factor is to set a Flag FLAG_DIM_BEHIND for the window.

Now the result is yours. Hope it will helpful for someone...

            WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();
            lp.dimAmount=0.6f;
            dialog.getWindow().setAttributes(lp);
            dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
Evocation answered 6/4, 2022 at 10:6 Comment(0)
P
0

My solution was to create a popup that takes up the entire size of the parent:

int width = ConstraintLayout.LayoutParams.MATCH_PARENT;
int height = ConstraintLayout.LayoutParams.MATCH_PARENT;
final PopupWindow popupWindow = new PopupWindow(popupView, width, height, focusable);

Then, in the xml layout of the popup, I set the background translucent and created a child layout that matches the constraints of its children and has a solid background. This dims everything behind the contents of the child ConstraintLayout.

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#60000000">


    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#FFFFFF"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent">

<!-- Child Components Here -->

    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Pindling answered 29/3 at 13:47 Comment(0)
P
-1

This code work

        pwindo = new PopupWindow(layout, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
        pwindo.showAtLocation(layout, Gravity.CENTER, 0, 0);
        pwindo.setOutsideTouchable(false);

        View container = (View) pwindo.getContentView().getParent();
        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;
        wm.updateViewLayout(container, p);
Protagonist answered 19/5, 2017 at 9:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.