Android 如何设置 DialogFragment 的宽度和高度?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12478520/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 10:46:43  来源:igfitidea点击:

How to set DialogFragment's width and height?

androidandroid-fragmentsandroid-dialogandroid-dialogfragment

提问by Adil Hussain

I specify the layout of my DialogFragment in an xml layout file (let's call it layout_mydialogfragment.xml), and its layout_widthand layout_heightattributes particularly (to be 100dpeach let's say). I then inflate this layout in my DialogFragment's onCreateView(...)method as follows:

我在 xml 布局文件中指定了我的 DialogFragment 的布局(我们称之为layout_mydialogfragment.xml),特别是它的layout_widthlayout_height属性(100dp让我们说每个人)。然后我在我的 DialogFragmentonCreateView(...)方法中扩展这个布局,如下所示:

View view = inflater.inflate(R.layout.layout_mydialogfragment, container, false);

Unfortunately, I find that when my dialog (DialogFragment) appears, it does not respect the layout_widthand layout_heightspecified in its xml layout file (and my dialog shrinks or expands variably depending on content). Anyone know whether or how I can get my dialog to respect the layout_widthand layout_heightspecified in its xml layout file? At the moment I'm having to specify the width and height of my dialog again in my DialogFragment's onResume()method as follows...

不幸的是,我发现当我的对话框 (DialogFragment) 出现时,它不遵守其 xml 布局文件中指定的layout_widthlayout_height(并且我的对话框根据内容不同地缩小或扩展)。任何人都知道我是否或如何让我的对话框尊重其 xml 布局文件中指定的layout_widthlayout_height?目前,我必须在 DialogFragment 的onResume()方法中再次指定对话框的宽度和高度,如下所示...

getDialog().getWindow().setLayout(width, height);

... And thus, undesirably, have to remember to make any future changes to the dialog's width and height in two places.

......因此,不希望出现的是,必须记住在两个地方对对话框的宽度和高度进行任何未来的更改。

采纳答案by Blix247

If you convert directly from resources values:

如果直接从资源值转换:

int width = getResources().getDimensionPixelSize(R.dimen.popup_width);
int height = getResources().getDimensionPixelSize(R.dimen.popup_height);        
getDialog().getWindow().setLayout(width, height);

Then specify match_parent in your layout for the dialog:

然后在对话框的布局中指定 match_parent :

android:layout_width="match_parent"
android:layout_height="match_parent"

You only have to worry about one place (place it in your DialogFragment#onResume). Its not perfect, but at least it works for having a RelativeLayout as the root of your dialog's layout file.

你只需要担心一个地方(把它放在你的DialogFragment#onResume)。它并不完美,但至少它适用于将 RelativeLayout 作为对话框布局文件的根。

回答by jmaculate

I ended up overriding Fragment.onResume()and grabbing the attributes from the underlying dialog, then setting width/height params there. I set the outermost layout height/width to match_parent. Note that this code seems to respect the margins I defined in the xml layout as well.

我最终覆盖Fragment.onResume()并从底层对话框中获取属性,然后在那里设置宽度/高度参数。我将最外面的布局高度/宽度设置为match_parent. 请注意,此代码似乎也尊重我在 xml 布局中定义的边距。

@Override
public void onResume() {
    super.onResume();
    ViewGroup.LayoutParams params = getDialog().getWindow().getAttributes();
    params.width = LayoutParams.MATCH_PARENT;
    params.height = LayoutParams.MATCH_PARENT;
    getDialog().getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
}

回答by Jose_GD

I got a fixed size DialogFragment defining the following in the XML main layout (LinearLayout in my case):

我得到了一个固定大小的 DialogFragment,它在 XML 主布局中定义了以下内容(在我的例子中是 LinearLayout):

android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="1000dp"
android:minHeight="450dp"

回答by Rodrigo

The only thing that worked in my case was the solution pointed here: http://adilatwork.blogspot.mx/2012/11/android-dialogfragment-dialog-sizing.html

在我的情况下唯一有效的是这里指出的解决方案:http: //adilatwork.blogspot.mx/2012/11/android-dialogfragment-dialog-sizing.html

Snippet from Adil blog post:

来自 Adil 博客文章的片段:

@Override
public void onStart()
{
  super.onStart();

  // safety check
  if (getDialog() == null)
    return;

  int dialogWidth = ... // specify a value here
  int dialogHeight = ... // specify a value here

  getDialog().getWindow().setLayout(dialogWidth, dialogHeight);

  // ... other stuff you want to do in your onStart() method
}

回答by jpmcosta

One way to control your DialogFragment's width and height is to make sure its dialog respects your view's width and height if their value is WRAP_CONTENT.

控制你DialogFragment的宽度和高度的一种方法是确保它的对话框尊重你的视图的宽度和高度,如果它们的值为WRAP_CONTENT

Using ThemeOverlay.AppCompat.Dialog

使用 ThemeOverlay.AppCompat.Dialog

One simple way to achieve this is to make use of the ThemeOverlay.AppCompat.Dialogstyle that's included in Android Support Library.

实现此目的的一种简单方法是利用ThemeOverlay.AppCompat.DialogAndroid 支持库中包含的样式。

DialogFragmentwith Dialog:

DialogFragmentDialog

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    Dialog dialog = new Dialog(getContext(), R.style.ThemeOverlay_AppCompat_Dialog);
    dialog.setContentView(view);
    return dialog;
}

DialogFragmentwith AlertDialog(caveat: minHeight="48dp"):

DialogFragmentAlertDialog(警告:)minHeight="48dp"

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    AlertDialog.Builder builder = new AlertDialog.Builder(getContext(), R.style.ThemeOverlay_AppCompat_Dialog);
    builder.setView(view);
    return builder.create();
}


You can also set ThemeOverlay.AppCompat.Dialogas the default theme when creating your dialogs, by adding it to your app's xml theme.
Be careful, as many dialogs do need the default minimum width to look good.

您还可以ThemeOverlay.AppCompat.Dialog在创建对话框时将其设置为默认主题,方法是将其添加到应用程序的 xml 主题中。
小心,因为许多对话框确实需要默认的最小宽度才能看起来不错。

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- For Android Dialog. -->
    <item name="android:dialogTheme">@style/ThemeOverlay.AppCompat.Dialog</item>

    <!-- For Android AlertDialog. -->
    <item name="android:alertDialogTheme">@style/ThemeOverlay.AppCompat.Dialog</item>

    <!-- For AppCompat AlertDialog. -->
    <item name="alertDialogTheme">@style/ThemeOverlay.AppCompat.Dialog</item>

    <!-- Other attributes. -->
</style>

DialogFragmentwith Dialog, making use of android:dialogTheme:

DialogFragmentDialog,使得使用android:dialogTheme

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    Dialog dialog = new Dialog(getContext());
    dialog.setContentView(view);
    return dialog;
}

DialogFragmentwith AlertDialog, making use of android:alertDialogThemeor alertDialogTheme(caveat: minHeight="48dp"):

DialogFragmentAlertDialog,利用android:alertDialogThemealertDialogTheme(警告:)minHeight="48dp"

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
    builder.setView(view);
    return builder.create();
}


Bonus

奖金

On Older Android APIs, Dialogs seem to have some width issues, because of their title (even if you don't set one).
If you don't want to use ThemeOverlay.AppCompat.Dialogstyle and your Dialogdoesn't need a title (or has a custom one), you might want to disable it:

在较旧的 Android API 上,Dialogs 似乎有一些宽度问题,因为它们的标题(即使您没有设置)。
如果您不想使用ThemeOverlay.AppCompat.Dialog样式并且Dialog不需要标题(或具有自定义标题),则可能需要禁用它:

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    Dialog dialog = new Dialog(getContext());
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.setContentView(view);
    return dialog;
}


Outdated answer, won't work in most cases

过时的答案,在大多数情况下不起作用

I was trying to make the dialog respect the width and height of my layout, without specifying a fixed size programmatically.

我试图让对话框尊重我的布局的宽度和高度,而不以编程方式指定固定大小。

I figured that android:windowMinWidthMinorand android:windowMinWidthMajorwere causing the problem. Even though they were not included in the theme of my Activityor Dialog, they were still being applied to the Activitytheme, somehow.

我想到了这一点android:windowMinWidthMinorandroid:windowMinWidthMajor并导致了问题。即使它们不包含在 myActivity或的主题中Dialog,它们仍然以Activity某种方式应用于主题。

I came up with three possible solutions.

我想出了三种可能的解决方案。

Solution 1:create a custom dialog theme and use it when creating the dialog in the DialogFragment.

解决方案一:创建自定义对话框主题,在DialogFragment.

<style name="Theme.Material.Light.Dialog.NoMinWidth" parent="android:Theme.Material.Light.Dialog">
    <item name="android:windowMinWidthMinor">0dip</item>
    <item name="android:windowMinWidthMajor">0dip</item>
</style>
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new Dialog(getActivity(), R.style.Theme_Material_Light_Dialog_NoMinWidth);
}

Solution 2:create a custom theme to be used in a ContextThemeWrapperthat will serve as Contextfor the dialog. Use this if you don't want to create a custom dialog theme (for instance, when you want to use the theme specified by android:dialogTheme).

解决方法2:创建一个使用自定义主题ContextThemeWrapper,将作为Context该对话框。如果您不想创建自定义对话框主题(例如,当您想使用由 指定的主题时),请使用此选项android:dialogTheme

<style name="Theme.Window.NoMinWidth" parent="">
    <item name="android:windowMinWidthMinor">0dip</item>
    <item name="android:windowMinWidthMajor">0dip</item>
</style>
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new Dialog(new ContextThemeWrapper(getActivity(), R.style.Theme_Window_NoMinWidth), getTheme());
}

Solution 3 (with an AlertDialog):enforce android:windowMinWidthMinorand android:windowMinWidthMajorinto the ContextThemeWrappercreated by the AlertDialog$Builder.

解决方案 3(带有AlertDialog):强制android:windowMinWidthMinorandroid:windowMinWidthMajor进入ContextThemeWrapperAlertDialog$Builder.

<style name="Theme.Window.NoMinWidth" parent="">
    <item name="android:windowMinWidthMinor">0dip</item>
    <item name="android:windowMinWidthMajor">0dip</item>
</style>
@Override
public final Dialog onCreateDialog(Bundle savedInstanceState) {
    View view = new View(); // Inflate your view here.
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setView(view);
    // Make sure the dialog width works as WRAP_CONTENT.
    builder.getContext().getTheme().applyStyle(R.style.Theme_Window_NoMinWidth, true);
    return builder.create();
}

回答by rmirabelle

Gotcha #13: DialogFragmentLayouts

陷阱 #13:DialogFragment布局

It's sort of mind numbing really.

真的有点伤脑筋。

When creating a DialogFragment, you can choose to override onCreateView(which passes a ViewGroupto attach your .xml layout to) or onCreateDialog, which does not.

创建 时DialogFragment,您可以选择覆盖onCreateView(传递 aViewGroup以将 .xml 布局附加到)或onCreateDialog不覆盖。

You mustn't override both methods tho, because you will very likely confuse Android as to when or if your dialog's layout was inflated! WTF?

您不能覆盖这两种方法,因为您很可能会混淆 Android 何时或是否膨胀对话框的布局!跆拳道?

The choice of whether to override OnCreateDialogor OnCreateViewdepends on how you intend to use the dialog.

选择是覆盖OnCreateDialog还是OnCreateView取决于您打算如何使用该对话框。

  • If you will launch the dialog in a window (the normal behavior), you are expected to override OnCreateDialog.
  • If you intend to embed the dialog fragment within an existing UI layout (FAR less common), then you are expected to override OnCreateView.
  • 如果您将在窗口中启动对话框(正常行为),您应该覆盖OnCreateDialog.
  • 如果您打算将对话框片段嵌入到现有的 UI 布局中(不太常见),那么您应该覆盖OnCreateView.

This is possibly the worst thing in the world.

这可能是世界上最糟糕的事情。

onCreateDialogInsanity

onCreateDialog疯狂

So, you're overriding onCreateDialogin your DialogFragmentto create a customized instance of AlertDialogto display in a window. Cool. But remember, onCreateDialogreceives no ViewGroupto attach your custom .xml layout to. No problem, you simply pass nullto the inflatemethod.

因此,您将覆盖onCreateDialogDialogFragment的创建自定义实例AlertDialog以在窗口中显示。凉爽的。但请记住,onCreateDialog收到 noViewGroup将您的自定义 .xml 布局附加. 没问题,您只需传递nullinflate方法。

Let the madness begin.

让疯狂开始吧。

When you override onCreateDialog, Android COMPLETELY IGNORESseveral attributes of the root node of the .xml Layout you inflate. This includes, but probably isn't limited to:

当您覆盖 时onCreateDialog,Android完全忽略您膨胀的 .xml 布局的根节点的几个属性。这包括但可能不限于:

  • background_color
  • layout_gravity
  • layout_width
  • layout_height
  • background_color
  • layout_gravity
  • layout_width
  • layout_height

This is almost comical, as you are required to set the layout_widthand layout_heightof EVERY .xml Layout or Android Studio will slap you with a nice little red badge of shame.

这几乎是可笑的,因为您需要设置每个 .xml 布局的layout_widthlayout_height,否则 Android Studio 会给您一个漂亮的红色小徽章。

Just the wordDialogFragmentmakes me want to puke. I could write a novel filled with Android gotchas and snafus, but this one is one of the most insideous.

光是一句话DialogFragment就想吐。我可以写一本充满 Android 陷阱和混乱的小说,但这是最内行的小说之一。

To return to sanity, first, we declare a style to restore JUST the background_colorand layout_gravitywe expect:

为了恢复理智,首先,我们声明一个样式来恢复 JUSTbackground_color并且layout_gravity我们期望:

<style name="MyAlertDialog" parent="Theme.AppCompat.Dialog">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:layout_gravity">center</item>
</style>

The style above inherits from the base theme for Dialogs (in the AppCompattheme in this example).

上面的样式继承自 Dialogs 的基本主题(AppCompat在本例中的主题中)。

Next, we applythe style programmatically to put back the values Android just tossed aside and to restore the standard AlertDialoglook and feel:

接下来,我们以编程方式应用样式来放回 Android 刚刚丢弃的值并恢复标准AlertDialog外观和感觉:

public class MyDialog extends DialogFragment {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        View layout = getActivity().getLayoutInflater().inflate(R.layout.my_dialog_layout, null, false);
        assert layout != null;
        //build the alert dialog child of this fragment
        AlertDialog.Builder b = new AlertDialog.Builder(getActivity());
        //restore the background_color and layout_gravity that Android strips
        b.getContext().getTheme().applyStyle(R.style.MyAlertDialog, true);
        b.setView(layout);
        return b.create();
    }
}

The code above will make your AlertDialoglook like an AlertDialogagain. Maybe this is good enough.

上面的代码会让你AlertDialog看起来像一个AlertDialog。也许这已经足够了。

But wait, there's more!

但是等等,还有更多!

If you're looking to set a SPECIFIClayout_widthor layout_heightfor your AlertDialogwhen it's shown (very likely), then guess what, you ain't done yet!

如果你正在寻找设置特定layout_widthlayout_heightAlertDialog时,它的显示(极有可能),那么你猜怎么着,你还没有完成!

The hilarity continues as you realize that if you attempt to set a specific layout_widthor layout_heightin your fancy new style, Android will completely ignore that, too!:

当你意识到如果你试图设置一个特定的layout_widthlayout_height你喜欢的新风格时,热闹还在继续,Android 也会完全忽略它!:

<style name="MyAlertDialog" parent="Theme.AppCompat.Dialog">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:layout_gravity">center</item>
    <!-- NOPE!!!!! --->
    <item name="android:layout_width">200dp</item>
    <!-- NOPE!!!!! --->
    <item name="android:layout_height">200dp</item>
</style>

To set a SPECIFIC window width or height, you get to head on over to a whole 'nuther method and deal with LayoutParams:

要设置特定的窗口宽度或高度,您可以使用整个 'nuther 方法并处理LayoutParams

@Override
public void onResume() {
    super.onResume();
    Window window = getDialog().getWindow();
    if(window == null) return;
    WindowManager.LayoutParams params = window.getAttributes();
    params.width = 400;
    params.height = 400;
    window.setAttributes(params);
}

Many folks follow Android's bad example of casting WindowManager.LayoutParamsup to the more general ViewGroup.LayoutParams, only to turn right around and cast ViewGroup.LayoutParamsback down to WindowManager.LayoutParamsa few lines later. Effective Java be damned, that unnecessary casting offers NOTHING other than making the code even harder to decipher.

Side note: There are some TWENTY repetitions of LayoutParamsacross the Android SDK - a perfect example of radically poor design.

许多人遵循 Android 的坏例子,将WindowManager.LayoutParams其转换为更一般的ViewGroup.LayoutParams,只是右转并稍后ViewGroup.LayoutParams返回到WindowManager.LayoutParams几行。该死的有效 Java,这种不必要的转换只会使代码更难破译。

旁注:LayoutParamsAndroid SDK 中有一些 200 次重复——这是设计极差的完美例子。

In Summary

总之

For DialogFragments that override onCreateDialog:

对于DialogFragment覆盖的 s onCreateDialog

  • To restore the standard AlertDialoglook and feel, create a style that sets background_color= transparentand layout_gravity= centerand apply that style in onCreateDialog.
  • To set a specific layout_widthand/or layout_height, do it programmatically in onResumewith LayoutParams
  • To maintain sanity, try not to think about the Android SDK.
  • 要恢复标准的AlertDialog外观和感觉,请创建一个设置background_color=transparentlayout_gravity= 的center样式并将该样式应用到onCreateDialog.
  • 要设置特定的layout_width和/或layout_height,请以编程方式onResume使用LayoutParams
  • 为了保持理智,尽量不要考虑 Android SDK。

回答by Andrey

When I need to make the DialogFragment a bit wider I'm setting minWidth:

当我需要使 DialogFragment 更宽时,我正在设置 minWidth:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:minWidth="320dp"
    ... />

回答by N1hk

I don't see a compelling reason to override onResumeor onStartto set the width and height of the Windowwithin DialogFragment's Dialog-- these particular lifecycle methods can get called repeatedly and unnecessarily execute that resizing code more than once due to things like multi window switching, backgrounding then foregrounding the app, and so on. The consequences of that repetition are fairly trivial, but why settle for that?

我看不出一个令人信服的理由来覆盖onResumeonStart设置的宽度和高度Window范围内DialogFragmentDialog-这些特定的生命周期方法可以得到反复和不必要的称为执行该调整的代码不止一次因之类的多窗口切换,backgrounding然后将应用程序置于前台,依此类推。这种重复的后果相当微不足道,但为什么要满足于此呢?

Setting the width/height instead within an overridden onActivityCreated()method will be an improvement because this method realistically only gets called once per instance of your DialogFragment. For example:

在重写的onActivityCreated()方法中设置宽度/高度将是一种改进,因为实际上每个DialogFragment. 例如:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    Window window = getDialog().getWindow();
    assert window != null;

    WindowManager.LayoutParams layoutParams = window.getAttributes();
    layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
    window.setAttributes(layoutParams);
}

Above I just set the width to be match_parentirrespective of device orientation. If you want your landscape dialog to not be so wide, you can do a check of whether getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAITbeforehand.

上面我只是将宽度设置为match_parent与设备方向无关。如果您希望您的横向对话框不那么宽,您可以getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT事先检查是否。

回答by Kelly

The dimension in outermost layout doesn't work in dialog. You can add a layout where set dimension below the outermost.

最外层布局中的尺寸在对话框中不起作用。您可以添加一个布局,其中在最外层下方设置尺寸。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<LinearLayout
    android:layout_width="xxdp"
    android:layout_height="xxdp"
    android:orientation="vertical">

</LinearLayout>

回答by NameSpace

Here's a way to set DialogFragment width/height in xml. Just wrap your viewHierarchy in a Framelayout (any layout will work) with a transparent background.

这是一种在 xml 中设置 DialogFragment 宽度/高度的方法。只需将您的 viewHierarchy 包装在具有透明背景的 Framelayout(任何布局都可以)中。

A transparent background seems to be a special flag, because it automatically centers the frameLayout's child in the window when you do that. You will still get the full screen darkening behind your fragment, indicating your fragment is the active element.

透明背景似乎是一个特殊的标志,因为当您这样做时,它会自动将 frameLayout 的子元素置于窗口的中心。您仍然会在片段后面全屏变暗,表明您的片段是活动元素。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/transparent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:background="@color/background_material_light">

      .....