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

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

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

不幸的是,我发现当我的对话框(DialogFragment)出现时,它不尊重在其xml布局文件中指定的layout_widthlayout_height (并且我的对话框根据内容不断缩小或扩大)。 任何人都知道是否可以让我的对话框尊重在其布局文件中指定的layout_widthlayout_height ? 此刻我不得不在我的DialogFragment的onResume()方法中再次指定我的对话框的宽度和高度,如下所示…

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

…因此,不必要的是,必须记住将来对对话的宽度和高度进行两处修改。

如果您直接从资源值转换:

 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 )。 它不完美,但至less它有一个RelativeLayout作为对话框的布局文件的根。

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

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

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

 @Override public void 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); super.onResume(); } 

在我的情况下工作的唯一的东西是在这里指出的解决scheme: 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 } 

我试图让对话尊重我的布局的宽度和高度,没有以编程方式指定一个固定的大小。

我想, android:windowMinWidthMinorandroid:windowMinWidthMajor是造成这个问题。 即使它们不包含在我的ActivityDialog的主题中,它们仍然以某种方式应用于Activity主题。

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

解决scheme1:创build自定义对话框主题,并在DialogFragment创build对话框时使用它。

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

解决scheme2:创build一个用于ContextThemeWrapper的自定义主题,该主题将用作对话框的Context 。 如果您不想创build自定义对话框主题(例如,当您想使用由android:dialogTheme指定的主题),请使用此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()); } 

解决scheme3(带有AlertDialog ):AlertDialog$Builder创build的AlertDialog$Builder强制执行android:windowMinWidthMinorandroid:windowMinWidthMajor

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

DialogFragment #13: DialogFragment布局

这真是麻木的。

当创build一个DialogFragment ,你可以select覆盖onCreateView (它传递一个ViewGroup来附加你的.xml布局)或onCreateDialog ,而不是。

你不能重写这两个方法,因为你很可能会混淆Android时,或者如果你的对话框的布局膨胀! WTF?

是否重写OnCreateDialogOnCreateView取决于您打算如何使用对话框。

  • 如果您将在窗口中启动对话框(正常行为),则需要覆盖OnCreateDialog
  • 如果您打算将对话框片段embedded到现有的UI布局中(不常见),那么您应该重写OnCreateView

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

onCreateDialog疯狂

因此,您在DialogFragment重写DialogFragment以创build一个DialogFragment的自定义实例以显示在窗口中。 凉。 但请记住, onCreateDialog不会收到任何ViewGroup以将自定义的.xml布局附加 。 没问题,只需将null传递给inflate方法。

让疯狂开始。

当你重写onCreateDialog ,Android COMPLETELY IGNORES会膨胀.xml布局根节点的几个属性。 这包括但不限于:

  • background_color
  • layout_gravity
  • layout_width
  • layout_height

这几乎是滑稽的,因为您需要设置每个.xml布局的layout_widthlayout_height ,否则Android Studio会用一个可爱的小红帽来鞭打你。

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

为了回到理智状态,首先,我们声明一个样式来恢复我们期望的background_colorlayout_gravity

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

上面的样式inheritance自对话框的基本主题(在本例中是AppCompat主题)。

接下来,我们通过编程的方式来应用样式,以恢复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(); } } 

上面的代码将使AlertDialog再次像AlertDialog一样。 也许这是够好的。

但是等等,还有更多!

如果你正在为你的AlertDialog设置一个特定的 layout_widthlayout_height ,当它显示(非常可能),那么猜测你还没有完成!

随着你意识到,如果你试图用你自己喜欢的新风格来设置一个特定的layout_width或者layout_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> 

要设置一个特定的窗口宽度或高度,你可以进入一个完整的方法,处理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); } 

许多人遵循Android的糟糕的例子,将WindowManager.LayoutParams强制转换为更一般的ViewGroup.LayoutParams ,只是右转,然后将ViewGroup.LayoutParams强制转换回WindowManager.LayoutParams 。 有效的Java是该死的,除了使代码更难破译以外,不必要的铸造只能提供任何东西。

附注:在Android SDK中有几十次LayoutParams重复 – 这是devise极其糟糕的完美例子。

综上所述

对于覆盖onCreateDialog DialogFragment

  • 要恢复标准的AlertDialog外观,请创build一个设置background_color = transparentlayout_gravity = center样式,并在onCreateDialog应用该样式。
  • 要设置特定的layout_width和/或layout_height ,请使用LayoutParams编程方式在onResume执行此操作
  • 为了保持理智,请不要考虑Android SDK。

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

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

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

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

这是一个设置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"> ..... 

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

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

我使用AlertDialog.Builder创build对话框,所以我在一个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)); } }); 

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

在Android 6.0上工作,遇到了同样的问题。 无论在自定义视图的根Layout设置的实际width如何, AlertDialog都将默认为在主题中设置的预定义width 。 我能够得到它设置正确调整的loading_message TextViewwidth 。 没有进一步调查,看起来大小的实际元素和具有根Layout环绕他们使其工作正常。 下面是一个正确设置对话框width的加载对话框的XML布局。 使用这个库的animation。

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/custom_color" android:padding="@dimen/custom_dimen"> <com.github.rahatarmanahmed.cpv.CircularProgressView xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/progress_view" android:layout_width="40dp" android:layout_height="40dp" android:layout_centerHorizontal="true" app:cpv_color="@color/white" app:cpv_animAutostart="true" app:cpv_indeterminate="true" /> <TextView android:id="@+id/loading_message" android:layout_width="100dp" android:layout_height="wrap_content" android:layout_below="@+id/progress_view" android:layout_centerHorizontal="true" android:gravity="center" android:textSize="18dp" android:layout_marginTop="@dimen/custom_dimen" android:textColor="@color/white" android:text="@string/custom_string"/> </RelativeLayout> 

你可以在下面的代码从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(); 

你可以使用百分比的宽度。

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

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

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

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

早期的解决scheme之一几乎工作。 我尝试了一些不同的东西,最终为我工作。

(确保你看他的解决scheme)这是他的解决scheme。 点击这里除了: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); 

最后一行是真正的不同。

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

要获得几乎覆盖整个scree的对话框:首先定义一个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()。setLayout()方法之前调用ScreenParamater

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