I specify the layout of my DialogFragment in an xml layout file (let's call it layout_mydialogfragment.xml
), and its layout_width
and layout_height
attributes particularly (to be 100dp
each let's say). I then inflate this layout in my DialogFragment's onCreateView(...)
method as follows:
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_width
and layout_height
specified 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_width
and layout_height
specified 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...
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.
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:
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.
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.
@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);
}
I got a fixed size DialogFragment defining the following in the XML main layout (LinearLayout in my case):
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="1000dp"
android:minHeight="450dp"
The only thing that worked in my case was the solution pointed here: http://adilatwork.blogspot.mx/2012/11/android-dialogfragment-dialog-sizing.html
Snippet from Adil blog post:
@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
}
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
.
Using ThemeOverlay.AppCompat.Dialog
One simple way to achieve this is to make use of the ThemeOverlay.AppCompat.Dialog
style that's included in Android Support Library.
DialogFragment
with 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(), R.style.ThemeOverlay_AppCompat_Dialog);
dialog.setContentView(view);
return dialog;
}
DialogFragment
with AlertDialog
(caveat: 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.Dialog
as 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.
<!-- 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>
DialogFragment
with Dialog
, making use of 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;
}
DialogFragment
with AlertDialog
, making use of android:alertDialogTheme
or alertDialogTheme
(caveat: 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, Dialog
s 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.Dialog
style and your Dialog
doesn't need a title (or has a custom one), you might want to disable it:
@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:windowMinWidthMinor
and android:windowMinWidthMajor
were causing the problem. Even though they were not included in the theme of my Activity
or Dialog
, they were still being applied to the Activity
theme, somehow.
I came up with three possible solutions.
Solution 1: create a custom dialog theme and use it when creating the dialog in the 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 ContextThemeWrapper
that will serve as Context
for 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
).
<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:windowMinWidthMinor
and android:windowMinWidthMajor
into the ContextThemeWrapper
created by the 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();
}
Gotcha #13: DialogFragment
Layouts
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
.
This is possibly 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. Cool. 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 insideous.
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.
When I need to make the DialogFragment a bit wider I'm setting minWidth:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="320dp"
... />
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>
I fixed it setting the root element layout parameters.
int width = activity.getResources().getDisplayMetrics().widthPixels;
int height = activity.getResources().getDisplayMetrics().heightPixels;
content.setLayoutParams(new LinearLayout.LayoutParams(width, height));
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.
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.
<?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">
.....
You can below code to set layout width and height from 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();
You can use percentage for width.
<style name="Theme.Holo.Dialog.MinWidth">
<item name="android:windowMinWidthMajor">70%</item>
I used Holo Theme for this example.
I don't see a compelling reason to override onResume
or onStart
to set the width and height of the Window
within 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?
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:
@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_parent
irrespective 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_PORTRAIT
beforehand.
I create the dialog using AlertDialog.Builder so I used Rodrigo's answer inside a OnShowListener.
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));
}
});
Working on Android 6.0, ran into the same issue. AlertDialog
would default to predefined width
set in the theme regardless of the actual width
set in the custom view's root Layout
. I was able to get it to set properly adjusting the width
of the loading_message
TextView
. Without investigating further, it seems that sizing the actual elements and having the root Layout
wrap around them makes it work as expected. Below is an XML layout of a loading dialog which sets width
of the the dialog correctly. Using the this library for the 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>
In my case it was caused by align_parentBottom="true"
given to a view inside a RelativeLayout
. Removed all the alignParentBottom's and changed all the layouts to vertical LinearLayouts and problem gone.
Set the Parent layout of Custom dialogue layout to RelativeLayout, get common width and height automatically .
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
Easy and solid:
@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();
}
This is the simplest solution
The best solution I have found is to override onCreateDialog()
instead of onCreateView()
. setContentView() will set the correct window dimensions before inflating. It removes the need to store/set a dimension, background color, style, etc in resource files and setting them manually.
@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;
}
One of the earlier solutions almost worked. I tried something slightly different and it ended up working for me.
(Make sure you look at his solution) This was his solution.. Click Here It worked except for: builder.getContext().getTheme().applyStyle(R.style.Theme_Window_NoMinWidth, true);
I changed it to
@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);
The last line is whats different really.
@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);
}
}
Add to your 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();
}
To get a Dialog that covers almost the entire scree: First define a ScreenParameter class
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;
}
}
Then you have to call the ScreenParamater before your getDialog.getWindow().setLayout() method
@Override
public void onResume()
{
super.onResume();
ScreenParameters s = new ScreenParameters();
getDialog().getWindow().setLayout(s.Width , s.Height);
}
来源:https://stackoverflow.com/questions/12478520/how-to-set-dialogfragments-width-and-height