如何设置DialogFragment的宽度和高度?
我在一个xml布局文件(我们称之为layout_mydialogfragment.xml
)中指定了DialogFragment的布局,特别是它的layout_width
和layout_height
属性( 100dp
每个都是100dp
)。 然后我在DialogFragment的onCreateView(...)
方法中膨胀这个布局,如下所示:
View view = inflater.inflate(R.layout.layout_mydialogfragment, container, false);
不幸的是,我发现当我的对话框(DialogFragment)出现时,它不尊重在其xml布局文件中指定的layout_width
和layout_height
(并且我的对话框根据内容不断缩小或扩大)。 任何人都知道是否可以让我的对话框尊重在其布局文件中指定的layout_width
和layout_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:windowMinWidthMinor
和android:windowMinWidthMajor
是造成这个问题。 即使它们不包含在我的Activity
或Dialog
的主题中,它们仍然以某种方式应用于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:windowMinWidthMinor
和android: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?
是否重写OnCreateDialog
或OnCreateView
取决于您打算如何使用对话框。
- 如果您将在窗口中启动对话框(正常行为),则需要覆盖
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_width
和layout_height
,否则Android Studio会用一个可爱的小红帽来鞭打你。
DialogFragment
这个词让我想呕吐。 我可以写一本充满Android陷阱和snafus的小说,但是这是一个最内在的。
为了回到理智状态,首先,我们声明一个样式来恢复我们期望的background_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>
上面的样式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_width
或layout_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
=transparent
和layout_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
TextView
的width
。 没有进一步调查,看起来大小的实际元素和具有根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); }