如何将对话框 window 背景设置为透明,而不影响其边距

How to set dialog window background to transparent, without affecting its margin

目前,我有以下对话框,我将对其项目执行展开/折叠动画。

此对话框是通过以下代码创建的

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

        // 
        int width = dialog.getWindow().getDecorView().getWidth();
        int height = dialog.getWindow().getDecorView().getHeight();
        dialog.getWindow().setLayout(width, height);
    }
});

但是,当执行动画时,副作用是这样的。

请注意,动画后对话框中不需要的额外白色区域不是由我们的自定义视图引起的。它是对话框本身的系统 window 白色背景。

我倾向于让系统window对话框的背景,变得透明。

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

虽然不再看到不需要的白色背景,但对话框的原始边距也消失了。 (对话框宽度现在是全屏宽度)

如何在不影响边距的情况下使其透明?

应该有的是你没有展示的东西,我不确定是你不知道的东西还是已经存在所以你认为没有必要展示。

将主题设置为 Dialog,将整个 activity 作为一个 Dialog。我不认为你这样做了,否则 AlertDialog 不会在那里。

我有点忘记你的描述了,但是有一点 <shape/> XML 比 9-patch 更强大,使用 RelativeLayout 会有所帮助。

作为兼容库一部分的背景图像abc_popup_background_mtrl_mult在图片信息​​中已经包含边距。

这就是当您删除背景图片时边距消失的原因。我强烈建议不要使用 ViewTreeObserver,它会被调用多次并可能导致性能问题。更好地使用屏幕尺寸:

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

您的问题出在布局上,请尝试使用层次结构查看器检查视图。

有一种非常简单的方法可以做到这一点:

您需要 "modify" 正在用作 Dialog 背景的 Drawable。那些 Dialogs 使用 InsetDrawable 作为背景。

API >= 23

只有 SDK API 23+ 允许您获取由 InsetDrawablegetDrawable() 方法)包装的源代码 Drawable。有了这个,你可以做任何你想做的事——例如将颜色更改为完全不同的颜色(例如 RED 或其他)。如果您使用这种方法,请记住包装的 DrawableGradientDrawable 而不是 ColorDrawable!

API < 23

对于较低的 API,您的 ("elegant") 选项非常有限。

幸运的是,您不需要将颜色更改为一些疯狂的值,只需将其更改为 TRANSPARENT。为此,您可以在 InsetDrawable.

上使用 setAlpha(...) 方法
InsetDrawable background = 
            (InsetDrawable) dialog.getWindow().getDecorView().getBackground();
background.setAlpha(0);

编辑(作为 Cheok Yan Cheng's 评论的结果):

或者您实际上可以跳过转换为 InsetDrawable 并获得相同的结果。请记住,这样做会导致 alphaInsetDrawable 本身上发生变化,而不是在 InsetDrawable.

包裹的 Drawable 上发生变化

尝试以下主题:

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

尝试使用以下代码将主题应用到 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);

希望对你有帮助!

只需在显示对话框后添加此行即可。我更喜欢使用 Dialog instedof 使用 AlertDialog

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

让我们从 Google 建议开始,建议使用 DialogFragment 而不是简单的 Dialog。

@rekire 由 drawable 设置的边距是正确的,未来它由 9 patch 或以编程方式设置,具体取决于主题。

因此您可以将填充设置为您的内容视图或使用 DialogFragment 创建对话框这里是一个根据内容更改对话框高度的示例,请注意您不需要使用如上所述的树观察器之前可能会导致性能问题。

所以例子

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>

注意:我将所有内容都包装到滚动视图中并设置了内边距,您可以根据需要跳过它。

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

最后你可以用这段代码显示你的对话框

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

我不会详细说明为什么 Fragment dialog 更好,但有一点很清楚,您可以为它封装逻辑并有单独的 class。 希望这能解决您的问题。