Set DialogFragment width and height
Let your daily dose of Android insanity commence.
Edit 2021
This article was originally written many years ago. Thankfully, it’s now considerably easier to control the width and height of your DialogFragment
. Sadly, it still must be done programmatically. But I’ve created a couple of extension methods for Kotlin that can reduce the code you need to write to this:
setWidthPercent(65)
or this:
setFullScreen()
Here are the extension methods:
Then in your DialogFragment
, in onActivityCreated
or later, you can simply do:
The remainder of this article is still worth a read, if for no other reason than understanding a little history and perhaps taking a little joy in my continued bashing of the Android SDK ;-)
It’s sort of mind numbing, really.
When creating a DialogFragment
, you can choose to override onCreateView
(which passes a ViewGroup
to attach your .xml layout to) or onCreateDialog
, which does not.
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?
The choice of whether to override OnCreateDialog
or OnCreateView
depends on how you intend to use the dialog.
- 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
.
Here’s yet another example of why the Android SDK the worst thing in the world.
onCreateDialog
Insanity
So, you’re overriding onCreateDialog
in your DialogFragment
to create a customized instance of AlertDialog
to display in a window. Kewl. But remember, onCreateDialog
receives no ViewGroup
to attach your custom .xml layout to. No problem, you simply pass null
to the inflate
method.
Let the madness begin.
When you override onCreateDialog
, Android COMPLETELY IGNORES several attributes of the root node of the .xml Layout you inflate. This includes, but probably isn't limited to:
background_color
layout_gravity
layout_width
layout_height
This is almost comical, as you are required to set the
layout_width
andlayout_height
of EVERY .xml Layout or Android Studio will slap you with a nice little red badge of shame.
Just the word DialogFragment
makes me want to puke. I could write a novel filled with Android gotchas and snafus, but this one is one of the most insidious.
To return to sanity, first, we declare a style to restore JUST the background_color
and layout_gravity
we expect:
<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 AppCompat
theme in this example).
Next, we apply the style programmatically to put back the values Android just tossed aside and to restore the standard AlertDialog
look and feel:
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 AlertDialog
look like an AlertDialog
again. Maybe this is good enough.
But wait, there’s more!
If you’re looking to set a SPECIFIC layout_width
or layout_height
for your AlertDialog
when it's shown (very likely), then guess what, you ain't done yet!
The hilarity continues as you realize that if you attempt to set a specific layout_width
or layout_height
in your fancy new style, Android will completely ignore that, too!:
<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
:
@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.LayoutParams
up to the more generalViewGroup.LayoutParams
, only to turn right around and castViewGroup.LayoutParams
back down toWindowManager.LayoutParams
a 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
LayoutParams
across the Android SDK - a perfect example of radically poor design.
In Summary
For DialogFragment
s that override onCreateDialog
:
- To restore the standard
AlertDialog
look and feel, create a style that setsbackground_color
=transparent
andlayout_gravity
=center
and apply that style inonCreateDialog
. - To set a specific
layout_width
and/orlayout_height
, do it programmatically inonResume
withLayoutParams
- To maintain sanity, try not to think about the Android SDK.