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

时间:2012-09-18 13:57:41

标签: android android-fragments android-dialog android-dialogfragment

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

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

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

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

...因此,不可取的是,必须记住在两个地方对对话框的宽度和高度进行任何改进。

26 个答案:

答案 0 :(得分:145)

如果直接从资源值转换:

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

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

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

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

答案 1 :(得分:90)

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

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

答案 2 :(得分:50)

在我的案例中唯一有用的是这里提出的解决方案:http://adilatwork.blogspot.mx/2012/11/android-dialogfragment-dialog-sizing.html

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
}

答案 3 :(得分:41)

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

使用ThemeOverlay.AppCompat.Dialog

实现此目的的一种简单方法是使用Android支持库中包含的ThemeOverlay.AppCompat.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;
}

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

您还可以在创建对话框时将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>

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

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

加成

在较旧的Android API上,Dialog似乎有一些宽度问题,因为它们的标题(即使您没有设置)。
如果您不想使用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;
}

过时的答案,在大多数情况下都不会工作

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

我认为android:windowMinWidthMinorandroid:windowMinWidthMajor导致了问题。即使它们未包含在我的ActivityDialog的主题中,但它们仍以某种方式应用于Activity主题。

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

解决方案1:创建自定义对话框主题,并在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);
}

解决方案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());
}

解决方案3(AlertDialog}:强制执行android:windowMinWidthMinorandroid:windowMinWidthMajorContextThemeWrapper创建的AlertDialog$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();
}

答案 4 :(得分:29)

陷阱#13:DialogFragment布局

真的麻木了。

创建DialogFragment时,您可以选择覆盖onCreateView(通过ViewGroup将.xml布局附加到)或onCreateDialog,而不是OnCreateDialog

  

你不能覆盖这两种方法,因为你很可能会混淆Android   至于何时或是否你的对话框布局被夸大了! WTF?

是否覆盖OnCreateViewOnCreateDialog的选择取决于您打算如何使用对话框。

  • 如果您要在窗口中启动对话框(正常行为),则应覆盖OnCreateView
  • 如果您打算在现有的UI布局中嵌入对话框片段(FAR不太常见),那么您应该覆盖onCreateDialog

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

onCreateDialog精神错乱

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

让疯狂开始。

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

  • layout_gravity
  • layout_width
  • layout_height
  • layout_width
  

这几乎是滑稽的,因为您需要设置每个.xml布局的layout_heightDialogFragment,否则Android Studio会为您带来一个漂亮的红色羞耻徽章。

只是 background_color让我想要呕吐。我可以写一本充满Android陷阱和snafus的小说,但这个是最内心的一个。

为了恢复理智,首先,我们声明一种样式来恢复我们期望的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>

AppCompat

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

接下来,我们以编程方式应用样式,将Android放弃的值放回原处并恢复标准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(); } } 外观:

AlertDialog

上面的代码会让您的AlertDialog再次看起来像layout_width。也许这还不错。

但等等,还有更多!

如果您希望layout_height AlertDialoglayout_widthlayout_height设置显示(非常可能) ,然后猜猜你还没完成!

如果你意识到如果你试图在你的新风格中设置一个特定的<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> LayoutParams,那么欢闹就会继续,Android也会完全忽略它!:

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

要设置SPECIFIC窗口的宽度或高度,您可以使用整个“nuther”方法并处理WindowManager.LayoutParams

ViewGroup.LayoutParams
  

许多人都遵循Android将ViewGroup.LayoutParams投射到更一般的WindowManager.LayoutParams的错误示例,只是向右转并将LayoutParams投回到DialogFragment几行之后。有效的Java被诅咒,除了使代码更难破译之外,不必要的铸造提供了许多东西。

     

附注:Android SDK中有一些onCreateDialog的重复次数 - 这是设计极其糟糕的完美示例。

摘要

覆盖AlertDialog的{​​{1}}:

  • 要恢复标准background_color外观,请创建一个设置transparent = layout_gravitycenter = onCreateDialog的样式,并将该样式应用于{ {1}}。
  • 要设置特定的layout_width和/或layout_height,请使用onResume
  • LayoutParams中以编程方式执行此操作
  • 为了保持理智,请尽量不要考虑Android SDK。

答案 5 :(得分:12)

当我需要使DialogFragment更宽一点时我设置minWidth:

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

答案 6 :(得分:6)

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

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

答案 7 :(得分:5)

我修复了它设置根元素布局参数。

int width = activity.getResources().getDisplayMetrics().widthPixels;
int height = activity.getResources().getDisplayMetrics().heightPixels;
content.setLayoutParams(new LinearLayout.LayoutParams(width, height));

答案 8 :(得分:5)

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

透明背景似乎是一个特殊标志,因为当你这样做时,它会自动将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">

      .....

答案 9 :(得分:4)

就我而言,DialogFragmentFragment一样占据了全部活动规模。 DialogFragment基于XML布局,而不是AlertDialog。我的错误是将对话框片段作为常规片段添加到FragmentManager

fragmentManager?.beginTransaction()?.run {
    replace(R.id.container, MyDialogFragment.newInstance(), MyDialogFragment.TAG)
    addToBackStack(MyDialogFragment.TAG)
}?.commitAllowingStateLoss()

相反,我需要show对话框片段:

val dialogFragment = MyDialogFragment.newInstance()
fragmentManager?.let { dialogFragment.show(it, MyDialogFragment.TAG) }

进行一些编辑后(我的布局中有ViewPager2),对话框片段变得太窄了:

enter image description here

我使用了N1hk的解决方案:

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    dialog?.window?.attributes?.width = ViewGroup.LayoutParams.MATCH_PARENT
    dialog?.window?.attributes?.height = ViewGroup.LayoutParams.MATCH_PARENT
}

现在,它已定义宽度和高度,而不是完整的活动大小。

我想谈谈onCreateViewonCreateDialog。如果您有一个基于布局的对话框片段,则可以使用这两种方法中的任何一种。

  1. 如果使用onCreateView,则应使用onActivityCreated设置宽度。

  2. 如果使用onCreateDialog而不是onCreateView,则可以在那里设置参数。不需要onActivityCreated

    onCreateDialog(savedInstanceState:Bundle?)的替代乐趣:对话框{ super.onCreateDialog(savedInstanceState)

     val view = activity?.layoutInflater?.inflate(R.layout.your_layout, null)
    
     val dialogBuilder = MaterialAlertDialogBuilder(context!!).apply { // Or AlertDialog.Builder(context!!).apply
         setView(view)
         // setCancelable(false)
     }
    
     view.text_view.text = "Some text"
    
     val dialog = dialogBuilder.create()
     // You can access dialog.window here, if needed.
    
     return dialog
    

    }

答案 10 :(得分:3)

您可以使用百分比作为宽度。

<style name="Theme.Holo.Dialog.MinWidth">
<item name="android:windowMinWidthMajor">70%</item>

我在这个例子中使用了Holo Theme。

答案 11 :(得分:3)

您可以在下面的代码中设置java的布局宽度和高度。

final AlertDialog alertDialog  = alertDialogBuilder.create();
final WindowManager.LayoutParams WMLP = alertDialog.getWindow().getAttributes();

WMLP.gravity = Gravity.TOP;
WMLP.y = mActionBarHeight;
WMLP.x = getResources().getDimensionPixelSize(R.dimen.unknown_image_width);

alertDialog.getWindow().setAttributes(WMLP);
alertDialog.show();

答案 12 :(得分:2)

这是科特林版本

    override fun onResume() {
        super.onResume()

        val params:ViewGroup.LayoutParams = dialog.window.attributes
        params.width = LinearLayout.LayoutParams.MATCH_PARENT
        params.height = LinearLayout.LayoutParams.MATCH_PARENT
        dialog.window.attributes = params as android.view.WindowManager.LayoutParams
    }

答案 13 :(得分:2)

我没有令人信服的理由覆盖onResume的{​​{1}}中的onStartWindow来设置DialogFragment的宽度和高度-这些特殊的生命周期方法可能会被重复调用,并且由于诸如多窗口切换,后台应用程序前台和前台应用程序等等之类的事情而导致不必要地多次执行该调整大小的代码。重复的结果相当琐碎,但是为什么要解决呢?

在覆盖的Dialog方法中设置宽度/高度而不是设置将是一项改进,因为该方法实际上每个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); } ,而与设备方向无关。如果您希望横向对话框的宽度不那么宽,则可以事先检查是否match_parent

答案 14 :(得分:2)

我使用AlertDialog.Builder创建对话框,所以我在OnShowListener中使用了Rodrigo的答案。

dialog.setOnShowListener(new OnShowListener() {

            @Override
            public void onShow(DialogInterface dialogInterface) {
                Display display = getWindowManager().getDefaultDisplay();
                DisplayMetrics outMetrics = new DisplayMetrics ();
                display.getMetrics(outMetrics);
                dialog.getWindow().setLayout((int)(312 * outMetrics.density), (int)(436 * outMetrics.density));
            }

        });

答案 15 :(得分:1)

将自定义对话框布局的父布局设置为 RelativeLayout ,自动获取常用的宽度和高度。

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

答案 16 :(得分:1)

这是最简单的解决方案

我找到的最佳解决方案是覆盖onCreateDialog()而不是onCreateView()。 setContentView()将在充气前设置正确的窗口尺寸。它消除了在资源文件中存储/设置尺寸,背景颜色,样式等并手动设置它们的需要。

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    Dialog dialog = new Dialog(getActivity());
    dialog.setContentView(R.layout.fragment_dialog);

    Button button = (Button) dialog.findViewById(R.id.dialog_button);
    // ...
    return dialog;
}

答案 17 :(得分:1)

简单明了:

@Override
    public void onResume() {
        // Sets the height and the width of the DialogFragment
        int width = ConstraintLayout.LayoutParams.MATCH_PARENT;
        int height = ConstraintLayout.LayoutParams.MATCH_PARENT;
        getDialog().getWindow().setLayout(width, height);

        super.onResume();
    }

答案 18 :(得分:1)

在我的情况下,它是由align_parentBottom="true"内部视图的RelativeLayout引起的。删除了所有的alignParentBottom并将所有布局更改为垂直LinearLayouts并且问题消失了。

答案 19 :(得分:0)

其他答案都不适合我。我只需要创建样式就可以解决这个问题,您可以在其中选择屏幕的百分比,您希望对话采用:

<style name="RelativeDialog" parent="android:style/Theme.Dialog">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowIsFloating">true</item>
    <item name="windowNoTitle">true</item>
    <item name="windowActionBar">false</item>
    <item name="windowFixedWidthMajor">90%</item>
    <item name="windowFixedWidthMinor">90%</item>
    <item name="android:windowMinWidthMajor">90%</item>
    <item name="android:windowMinWidthMinor">90%</item>
    <item name="android:colorBackgroundCacheHint">@null</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowAnimationStyle">@android:style/Animation</item>
</style>

不仅仅是将此样式设置为对话框,例如:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setStyle(STYLE_NO_TITLE, R.style.RelativeDialog)
}

答案 20 :(得分:0)

使用 RelativeLayout 作为 DialogFragment

的父级

答案 21 :(得分:0)

早期的解决方案之一几乎起作用。我尝试了一些稍微不同的东西,它最终为我工作。

(确保你看看他的解决方案) 这是他的解决方案.. Click Here 它的工作原理除外:builder.getContext()。getTheme()。applyStyle(R.style.Theme_Window_NoMinWidth,true);

我把它改成了

 @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {


        // Use the Builder class for convenient dialog construction
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

        // Get layout inflater
        LayoutInflater layoutInflater = getActivity().getLayoutInflater();

        // Set layout by setting view that is returned from inflating the XML layout
        builder.setView(layoutInflater.inflate(R.layout.dialog_window_layout, null));


        AlertDialog dialog = builder.create();

        dialog.getContext().setTheme(R.style.Theme_Window_NoMinWidth);

最后一行真的不同。

答案 22 :(得分:0)

这将很好地工作。

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

答案 23 :(得分:0)

添加到您的FragmentDialog

public void onResume() {
    Window window = getDialog().getWindow();
    Point size = new Point();
    Display display = window.getWindowManager().getDefaultDisplay();
    display.getSize(size);
    window.setLayout( (int)(size.x * 0.9), WindowManager.LayoutParams.WRAP_CONTENT );
    window.setGravity( Gravity.CENTER );
    super.onResume();
}

答案 24 :(得分:0)

@Override
public void onStart() {
    super.onStart();
    Dialog dialog = getDialog();
    if (dialog != null)
    {
        dialog.getWindow().setLayout(-1, -2);
        dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
        Window window = getDialog().getWindow();
        WindowManager.LayoutParams params = window.getAttributes();
        params.dimAmount = 1.0f;
        window.setAttributes(params);
        window.setBackgroundDrawableResource(android.R.color.transparent);
    }
}

答案 25 :(得分:-4)

要获得几乎覆盖整个scree的Dialog:首先定义一个ScreenParameter类

public class ScreenParameters
{
    public static int Width;
    public static  int Height;

    public ScreenParameters()
    {
        LayoutParams l = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
        Width= l.width;
        Height = l.height;
    }
}

然后你必须在getDialog.getWindow()之前调用ScreenParamater.setLayout()方法

@Override
public void onResume()
{
    super.onResume();
    ScreenParameters s = new ScreenParameters();
    getDialog().getWindow().setLayout(s.Width , s.Height);
}