15

Currently, I have the following dialog, which I will perform expand/ collapse animation on its items.

enter image description here

This dialog is created via the following code

import android.support.v7.app.AlertDialog;

final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final AlertDialog dialog = builder.setView(view).create();
final ViewTreeObserver vto = view.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

    public void onGlobalLayout() {
        ViewTreeObserver obs = view.getViewTreeObserver();
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
            obs.removeOnGlobalLayoutListener(this);
        } else {
            obs.removeGlobalOnLayoutListener(this);
        }

        // http://stackoverflow.com/questions/19326142/why-listview-expand-collapse-animation-appears-much-slower-in-dialogfragment-tha
        int width = dialog.getWindow().getDecorView().getWidth();
        int height = dialog.getWindow().getDecorView().getHeight();
        dialog.getWindow().setLayout(width, height);
    }
});

However, when animation being performed, here's the side effect.

enter image description here

Note, the unwanted extra white region at the dialog after animation, is not caused by our custom view. It is the system window white background of the dialog itself.

I tend to make the system window background of the dialog, to become transparent.

final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final AlertDialog dialog = builder.setView(view).create();
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

Although the unwanted white background is no longer seen, the original margin of the dialog is gone too. (The dialog width is now full screen width)

enter image description here

How can I make it transparent, without affecting its margin?

pRaNaY
  • 24,642
  • 24
  • 96
  • 146
Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875

6 Answers6

15

There's a pretty easy way to do that:

You need to "modify" the Drawable that is being used as a background of the Dialog. Those sort of Dialogs use an InsetDrawable as a background.

API >= 23

Only SDK API 23+ allows you to get the source Drawable wrapped by the InsetDrawable (getDrawable() method). With this, you can do whatever you want - e.g. change color to something completely different (like RED or something). If you use this approach remember that the wrapped Drawable is a GradientDrawable and not a ColorDrawable!

API < 23

For lower APIs your ("elegant") options are very limited.

Fortunately you don't need to change the color to some crazy value, you just need to change it to TRANSPARENT. For this you can use setAlpha(...) method on InsetDrawable.

InsetDrawable background = 
            (InsetDrawable) dialog.getWindow().getDecorView().getBackground();
background.setAlpha(0);

EDIT (as a result of Cheok Yan Cheng's comments):

or you can actually skip casting to InsetDrawable and get the same result. Just remember that doing so will cause the alpha to be changed on the InsetDrawable itself and not on the Drawable that is wrapped by the InsetDrawable.


retaining spacings

Bartek Lipinski
  • 30,698
  • 10
  • 94
  • 132
  • Seem like a promising way. Going to try it out tonight! – Cheok Yan Cheng Mar 24 '16 at 09:07
  • I had tried and it works as expected. However, I think the casting is not necessary. The following will work as well : `Drawable background = dialog.getWindow().getDecorView().getBackground(); background.setAlpha(0);` – Cheok Yan Cheng Mar 25 '16 at 13:41
  • @CheokYanCheng When you're not casting, the `alpha` is being changed for a different thing (for the `InsetDrawable` itself, instead for the `Drawable` wrapped inside the `InsetDrawable`). Still it actually might be not necessary. Changing `alpha` for the `InsetDrawable` indeed might give you the same result. – Bartek Lipinski Mar 25 '16 at 13:45
  • Hi, I had tested in 3 different version of Android. I can confirm without casting is working fine for me. – Cheok Yan Cheng Mar 25 '16 at 13:51
  • @CheokYanCheng awesome, I'm glad my answer helped you! – Bartek Lipinski Mar 25 '16 at 14:19
  • Do you find some way to make it work for SDK for API<=23 – Stefanija Jan 12 '17 at 10:12
  • @Merian are you asking for a solution for API<23 for changing the color to other than transparent? – Bartek Lipinski Jan 12 '17 at 10:19
  • 1
    Transparency this way works only for android 6.0 (API 23) and higher in API lower than that the background color of the root still remains to it's default – Stefanija Jan 12 '17 at 10:43
  • ok, I don't think you understood. My original answer includes a solution for API<23 to set background to transparent. Try to read the whole answer again. – Bartek Lipinski Jan 12 '17 at 10:53
2

Try to below Theme:

<style name="TransaparantDialog">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowFrame">@null</item>
    <item name="android:windowTitleStyle">@null</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:backgroundDimEnabled">false</item>
    <item name="android:background">@android:color/transparent</item>
    <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
</style>

Try below code to apply Theme to AlertDialog.Builder:

final AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(activity, R.style.TransaparantDialog));
...
dialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);

I hope help you !

pRaNaY
  • 24,642
  • 24
  • 96
  • 146
0

What should be there is what you didn't show, I'm not sure it is something you didn't know or it is already there so you don't think it is necessary to show.

Set theme to Dialog, that puts entire activity as one Dialog. I don't think you did it, otherwise AlertDialog would not be there.

I'm a bit lost your description, but there is that little <shape/> XML that is much more powerful then a 9-patch, and use RelativeLayout will help.

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
0

The background image abc_popup_background_mtrl_mult which is part of the compat library contains already a margin in the picture information.

abc_popup_background_mtrl_mult

This is why the margin goes away when you remove the background image. I strongly recommend not to use the ViewTreeObserver, it will been called multiple times and can cause performance issues. Better work with the screen size:

Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;

Your problem is properly in the layout try to check the views with the Hierarchy viewer.

rekire
  • 47,260
  • 30
  • 167
  • 264
  • I'm 100% sure the problem is not with my layout. As if I change the my dialog layout background to red color, the extra white still appear when animation happens. This problem doesn't occur, if I'm using dialog from old sherlock action bar library. – Cheok Yan Cheng Mar 24 '16 at 07:31
  • I'm more interested to know, how to you find out the background image used by dialog support library, I assume under different theme, the background image will be different too right? – Cheok Yan Cheng Mar 24 '16 at 07:32
  • I searched it month ago, basically I read the source code of the dialogs and checked the styles. That is painful however if you digged in multiple times you find that out fast. Did you check the Hierarchy viewer? That is a great tool to find out what is going on. – rekire Mar 24 '16 at 07:37
0

just add this line after show dialog. I would prefer using Dialog instedof using AlertDialog

dialog.getWindow().setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
0

Let's start with Google recommendation which says to use DialogFragment instead of a simple Dialog.

@rekire is right that margins set by drawable, going forward it is set by either 9 patch or programmatically depending on theme.

So you either can set your padding to your content view or create dialog using DialogFragment here is an example which changes height of dialog based on it's content, and note you don't need to use tree observer which is as mentioned before may cause performance issue.

So the example

dialog_confirm.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="20dp">

    <LinearLayout android:id="@+id/container"
                  xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:background="@android:color/white"
                  android:orientation="vertical"
                  android:animateLayoutChanges="true"
                  android:padding="15dp">

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:padding="10dp"
            android:text="A label text"
            android:textAppearance="?android:attr/textAppearanceLarge"/>

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:padding="10dp"
            android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque mauris mi, dictum a lectus ut, facilisis"
            android:textAppearance="?android:attr/textAppearanceMedium"/>

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="Remove Me"/>

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="Remove Me"/>

        <Button
            android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="Remove Me"/>

        <!-- as much content as you need -->

    </LinearLayout>
</ScrollView>

Note: I wrapped everything into scroll view and set padding you can skip it if you want.

ConfirmDialog.java

//here goes package name and  imports

/**
 * Created by Vilen - virtoos.com;
 * fragment dialog example
 */
public class ConfirmDialog extends DialogFragment implements View.OnClickListener {

    private Button button1;
    private Button button2;
    private Button button3;
    private LinearLayout containerLayout;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(DialogFragment.STYLE_NO_TITLE, 0);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.dialog_confirm, container, false);
        containerLayout = (LinearLayout)v.findViewById(R.id.container);
        button1 = (Button)v.findViewById(R.id.button1);
        button2 = (Button)v.findViewById(R.id.button2);
        button3 = (Button)v.findViewById(R.id.button3);
        button1.setOnClickListener(this);
        button2.setOnClickListener(this);
        button3.setOnClickListener(this);
        return v;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // make background transparent if you want
        //getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        return super.onCreateDialog(savedInstanceState);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.button1:
                containerLayout.removeView(button1);
                break;
            case R.id.button2:
                containerLayout.removeView(button2);
                break;
            case R.id.button3:
                containerLayout.removeView(button3);
                break;
        }
    }
}

and finally you can show your dialog with this piece of code

ConfirmDialog confirmDialog = new ConfirmDialog();
confirmDialog.show(getSupportFragmentManager(), "dialog");

enter image description here

I will not go into details why Fragment dialog is better but one thing is clear that you can encapsulate logic for it and have separate class. Hope this solves your issue.

Vilen
  • 5,061
  • 3
  • 28
  • 39