Android PopupWindow elevation does not show shadow
Asked Answered
A

3

39

Android PopupWindow does not show shadows when the elevation is set. It appears to support it from the documentation. I am using 5.0 Lollipop.

Creating the popup as follows:

    popupWindow = new PopupWindow(context);
    popupWindow.setOutsideTouchable(true);
    popupWindow.setFocusable(true);
    popupWindow.setElevation(10);
    popupWindow.setContentView(rootView);
    popupWindow.showAtLocation(anchorView, Gravity.NO_GRAVITY, xPos, yPos);
Aceto answered 2/12, 2014 at 21:47 Comment(5)
Are you getting shadows elsewhere in your app, e.g. from the ActionBar?Antiquarian
Yes, shadows work just fine everywhere else.Aceto
Patrick, were you able to fix this?Luben
I've filed a bug code.google.com/p/android/issues/detail?id=174866Luben
I had to roll my own solution.Aceto
L
36

As answered by an Android developer.

If the inflated view doesn't have a background set, or the popup window itself doesn't have a background set (or has a transparent background) then you won't get a shadow.

which was my case and seems to be yours, since you are not using setBackgroundDrawable.

This worked for me

popupWindow.setBackgroundDrawable(new ColorDrawable(Color.WHITE));

I've opened a new issue suggesting that they update the documentation (https://code.google.com/p/android/issues/detail?id=174919)

Luben answered 28/5, 2015 at 8:22 Comment(5)
What if I want to use a background drawable instead of color?Electrotechnics
@Dr.aNdRO implement the drop shadow into your drawableKigali
Thats what I did, Thanks !Electrotechnics
Searched for hours for the reason, why it is not working. ThanksKatt
What if I want to use a custom background drawable? Like a bubble? I don't see any shadowsWarfeld
T
22

For others who visit this answer and missed what the OP already had, you should set the elevation to create a shadow:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    popupWindow.setElevation(20);
}

PopupWindow with shadow

Depending on what your content view is, you might also need to set the background drawable, although this is not always necessary. If needed you can do as @Maragues suggested:

popupWindow.setBackgroundDrawable(new ColorDrawable(Color.WHITE));

To support pre-Lollipop devices you could use a 9-patch or image that includes the shadow within it.

Code

This is the code for the image above.

LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View popupView = inflater.inflate(R.layout.popup_window, null);
int width = LinearLayout.LayoutParams.WRAP_CONTENT;
int height = LinearLayout.LayoutParams.WRAP_CONTENT;
boolean focusable = true;
final PopupWindow popupWindow = new PopupWindow(popupView, width, height, focusable);
popupView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        popupWindow.dismiss();
        return true;
    }
});

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    popupWindow.setElevation(20);
}

popupWindow.showAtLocation(anyView, Gravity.CENTER, 0, 0);

Note:

The elevation is in pixels when set in code, but usually in dp when set in xml. You should convert a dp value to pixels when setting it in code.

Tushy answered 7/5, 2018 at 9:57 Comment(0)
T
4
  • setElevation was not showing a shadow, because my container was transparent
  • My container was transparent because I needed some padding on each side

Screenshot of the below code

  • I made three containers
  • Outer most container is transparent
  • Next container inside has a Drawable background with the shadow
  • Next container holds the actual content
  • Min width of the button inside the xml helps dictate the width. Same with the 2nd container's 12dp of padding.

Custom Popup Window class written in Kotlin:

class CustomPopupWindow(
    private val context: Context
) : PopupWindow(context) {

  init {
    val view = LayoutInflater.from(context).inflate(R.layout.popup_window_layout, null)
    contentView = view

    height = ListPopupWindow.WRAP_CONTENT
    width = ListPopupWindow.MATCH_PARENT
    isOutsideTouchable = true

    setTouchDismissListener()

    // set the background of the second container to the drawable
    // with the shadow to get our shadow
    contentView.findViewById<LinearLayout>(R.id.outer_content_container).setBackgroundDrawable(context.resources.getDrawable(R.drawable.background_shadow))
  }

  // Add a listener to dismiss the popup Window when someone
  // clicks outside of it
  private fun setTouchDismissListener() {
    setTouchInterceptor { _, event ->
      if (event != null && event.action == MotionEvent.ACTION_OUTSIDE) {
        dismiss()
        return@setTouchInterceptor true
      }
      false
    }
  }

  // this anchor view can be ANY view
  fun show(anchor: View) {

    // Remove the default background that is annoying
    setBackgroundDrawable(BitmapDrawable())

    // Grab the pixel count for how far down you want to put it.
    // toolbar_height is 56dp for me
    val yOffSetInPixels = context.resources.getDimensionPixelSize(R.dimen.toolbar_height)

    // Animation to make it appear and disappear like a Dialog
    animationStyle = android.R.style.Animation_Dialog

    // Show it
    showAtLocation(anchor, Gravity.TOP, 0, yOffSetInPixels)
  }
}

  • XML for Custom PopupWindow:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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="wrap_content"
  android:background="@android:color/transparent"
  android:orientation="vertical">

  <android.support.constraint.ConstraintLayout
    android:id="@+id/transparent_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:background="@android:color/transparent"
    android:padding="12dp">

    <LinearLayout
      android:id="@+id/outer_content_container"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:background="@color/white"
      android:orientation="vertical"
      app:layout_constraintBottom_toBottomOf="@+id/transparent_container"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/transparent_container">

      <LinearLayout
        android:id="@+id/content_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="12dp">

        <TextView
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="Header" />

        <LinearLayout
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:layout_gravity="center_vertical"
          android:layout_marginTop="8dp"
          android:orientation="horizontal">

          <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:paddingEnd="0dp"
            android:paddingStart="8dp"
            android:text="Message" />

        </LinearLayout>

        <TextView
          android:id="@+id/add_to_bag_button"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_marginTop="16dp"
          android:height="48dp"
          android:background="@color/gray"
          android:gravity="center"
          android:minWidth="350dp"
          android:text="BUTTON"
          android:textAllCaps="true" />

      </LinearLayout>

    </LinearLayout>

  </android.support.constraint.ConstraintLayout>

</LinearLayout>

  • Custom Drawable that shows a shadow:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

  <!-- Drop Shadow Stack -->
  <item>
    <shape>
      <padding
        android:bottom="1dp"
        android:left="1dp"
        android:right="1dp"
        android:top="0dp" />

      <solid android:color="#00CCCCCC" />

      <corners android:radius="3dp" />
    </shape>
  </item>
  <item>
    <shape>
      <padding
        android:bottom="1dp"
        android:left="1dp"
        android:right="1dp"
        android:top="0dp" />

      <solid android:color="#10CCCCCC" />

      <corners android:radius="3dp" />
    </shape>
  </item>
  <item>
    <shape>
      <padding
        android:bottom="1dp"
        android:left="1dp"
        android:right="1dp"
        android:top="0dp" />

      <solid android:color="#20CCCCCC" />

      <corners android:radius="3dp" />
    </shape>
  </item>
  <item>
    <shape>
      <padding
        android:bottom="1dp"
        android:left="1dp"
        android:right="1dp"
        android:top="0dp" />

      <solid android:color="#30CCCCCC" />

      <corners android:radius="3dp" />
    </shape>
  </item>
  <item>
    <shape>
      <padding
        android:bottom="1dp"
        android:left="1dp"
        android:right="1dp"
        android:top="0dp" />

      <solid android:color="#50CCCCCC" />

      <corners android:radius="3dp" />
    </shape>
  </item>

  <!-- Background -->
  <item>
    <shape>
      <solid android:color="@android:color/white" />

      <corners android:radius="0dp" />
    </shape>
  </item>

</layer-list>

  • Using it all:
val popupWindow = CustomPopupWindow(activity);
popupWindow.show(anyViewInYourActivity);
Trombidiasis answered 6/2, 2019 at 19:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.