【问题标题】:How to set dialog window background to transparent, without affecting its margin如何将对话框窗口背景设置为透明,而不影响其边距
【发布时间】:2019-09-25 14:53:19
【问题描述】:

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

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

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

但是,在执行动画时,会有副作用。

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

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

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

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

我怎样才能让它透明而不影响它的边距?

【问题讨论】:

  • 在视图中添加“填充”可能会有所帮助?
  • 没有。它不会有帮助。这是在自定义视图上添加填充后的样子 - i.imgur.com/x74qROQ.png
  • 请添加您的布局文件,我想问题就在那里。
  • 您可以创建一个带有透明背景的简单布局,而不是创建一个对话框。这也会更容易使用和维护
  • 您是否尝试了对话片段?

标签: android android-animation android-dialog


【解决方案1】:

有一个非常简单的方法来做到这一点:

您需要“修改”用作Dialog 背景的Drawable。那种Dialogs 使用InsetDrawable 作为背景。

API >= 23

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

API

对于较低的 API,您的(“优雅”)选项非常有限。

幸运的是,您不需要将颜色更改为某个疯狂的值,只需将其更改为TRANSPARENT。为此,您可以在InsetDrawable 上使用setAlpha(...) 方法。

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

编辑(由于Cheok Yan Cheng's cmets)

或者您实际上可以跳过转换为InsetDrawable 并获得相同的结果。请记住,这样做会导致 alpha 本身上的 alpha 被更改,而不是被 InsetDrawable 包裹的 Drawable 上。


【讨论】:

  • 看起来很有前途。今晚去试试!
  • 我试过了,它按预期工作。但是,我认为铸造是没有必要的。以下内容也可以:Drawable background = dialog.getWindow().getDecorView().getBackground(); background.setAlpha(0);
  • @CheokYanCheng 当你不投射时,alpha 被改变为不同的东西(InsetDrawable 本身,而不是包裹在InsetDrawable 中的Drawable)。不过实际上可能没有必要。将alpha 更改为InsetDrawable 确实可能会得到相同的结果。
  • 嗨,我已经在 3 个不同版本的 Android 中进行了测试。我可以确认不进行投射对我来说效果很好。
  • 这种方式的透明度仅适用于 android 6.0 (API 23) 和更高版本的 API,低于根的背景颜色仍保持默认值
【解决方案2】:

尝试以下主题:

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

希望能帮到你!

【讨论】:

    【解决方案3】:

    compat 库中的背景图片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;
    

    您的问题出在布局中尝试使用 Hierarchy 查看器检查视图。

    【讨论】:

    • 我 100% 确定问题不在于我的布局。就好像我将我的对话框布局背景更改为红色一样,当动画发生时,额外的白色仍然会出现。如果我使用旧的 sherlock 操作栏库中的对话框,则不会出现此问题。
    • 我比较有兴趣知道,如何找到对话框支持库使用的背景图片,我假设在不同的主题下,背景图片也会不同吧?
    • 一个月前我搜索过,基本上我阅读了对话框的源代码并检查了样式。这很痛苦,但是如果您多次挖掘,您会很快发现这一点。你检查了层次结构查看器吗?这是了解正在发生的事情的好工具。
    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      让我们从 Google 推荐开始,它说使用 DialogFragment 而不是简单的 Dialog。

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

      因此,您可以将填充设置为内容视图,也可以使用 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 对话框更好,但有一点很清楚,您可以为它封装逻辑并拥有单独的类。 希望这能解决您的问题。

      【讨论】:

        【解决方案6】:

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

        将主题设置为对话框,将整个活动作为一个对话框。我认为你没有这样做,否则 AlertDialog 不会出现。

        你的描述我有点记不清了,但是有一点 &lt;shape/&gt; XML 比 9-patch 更强大,使用 RelativeLayout 会有所帮助。

        【讨论】:

          猜你喜欢
          • 2015-05-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-04-23
          • 1970-01-01
          • 2017-03-11
          • 2016-03-25
          相关资源
          最近更新 更多