Blur or dim background when Android PopupWindow active Blur or dim background when Android PopupWindow active android android

Blur or dim background when Android PopupWindow active


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


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


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