Does anybody knows how can I set margins to a custom dialog? I\'m asking because I\'ve a custom dialog but when displayed it stretches to fill the parent, even though I set
Margin doesnt seem to work on the custom layout for the dialog, but padding works. Try setting the padding on the top level Linear layout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="4dp"
android:paddingRight="4dp" >
I was having trouble with the other solutions presented as the "OK" and "CANCEL" buttons went outside of the screen and it just looked weird. Instead, I used android:windowMinWidthMinor & android:windowMinWidthMajor which looked better and incidentally also required less code. Nothing is needed in Java / Kotlin.
Here's all I did:
1) Only use only one background drawable (I called mine dialog_box.xml)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/colorWhite" />
<corners android:radius="18dp" />
</shape>
2) Set background in Layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/dialog_box">
</androidx.constraintlayout.widget.ConstraintLayout>
3) Set style:
<item name="alertDialogTheme">@style/AlertDialogTheme</item>
<style name="AlertDialogTheme" parent="ThemeOverlay.AppCompat.Dialog.Alert">
<item name="android:background">@drawable/dialog_box</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowMinWidthMinor">85%</item>
</style>
A workaround can be done like this:
dialog.getWindow().getAttributes().height =
(int) (getDeviceMetrics(context).heightPixels*0.8);
`getDeviceMetrics Method:
public static DisplayMetrics getDeviceMetrics(Context context) {
DisplayMetrics metrics = new DisplayMetrics();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
display.getMetrics(metrics);
return metrics;
}
Margins don't work for Dialogs, I imagine the top-level window view isn't a layout type that supports margins. I've seen posts saying margins will work when defined as the Dialog's style (rather than on the top-level view element), but this does not seem to work either.
What you need to do to work around the issue is to use an inset
drawable for your Dialog background, and adjust any padding to account for the background's extra inset. In the example below, I'll just set left & right margins.
Dialog background drawable:
<?xml version="1.0" encoding="utf-8"?>
<!-- drawable is a reference to your 'real' dialog background -->
<!-- insetRight and insetLeft add the margins -->
<inset
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/dialog_background"
android:insetRight="10dp"
android:insetLeft="10dp">
</inset>
Dialog main view:
<?xml version="1.0" encoding="utf-8"?>
<!-- paddingTop / paddingBottom padding for the dialog -->
<!-- paddingLeft / paddingRight padding must add the additional inset space to be consistent -->
<!-- background references the inset background drawable -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:background="@drawable/dialog_background_inset">
<!-- ...the rest of the layout... -->
You may also need to set the background colour of the Dialog itself to transparent. Add a colour resource like so:
<color name="transparent">#00000000</color>
And set the window background colour of the dialog to this (note: you can't assign the colour directly, eclipse will complain)
<style name="Dialog" parent="android:style/Theme.Dialog">
<item name="android:windowBackground">@color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
</style>
This style should be passed to your Dialog's constructor as the theme
argument, as in new Dialog(context, R.style.Dialog);
As @simpleApps and @pospi pointed out, you need to add insets to the backgroundDrawable of the Dialog. If you are using a custom dialog, you can try with a drawable defined in a xml
dialog?.window?.setBackgroundDrawableResource(R.drawable.background_dialog)
where R.drawable.background_dialog is defined as
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="20dp"
android:insetTop="40dp"
android:insetRight="20dp"
android:insetBottom="40dp">
<shape android:shape="rectangle">
<solid android:color="@color/color_background_fragment" />
<corners android:radius="10dp" />
</shape>
</inset>
This is a straight-forward, programmatic way to set position and size of my dialog with margins.
I tested my approach for a DialogFragment
by applying it in the onCreateDialog
method:
public Dialog onCreateDialog( Bundle savedInstanceState )
{
// create dialog in an arbitrary way
Dialog dialog = super.onCreateDialog( savedInstanceState );
DialogUtils.setMargins( dialog, 0, 150, 50, 75 );
return dialog;
}
This is the method applying the margins to the dialog:
public static Dialog setMargins( Dialog dialog, int marginLeft, int marginTop, int marginRight, int marginBottom )
{
Window window = dialog.getWindow();
if ( window == null )
{
// dialog window is not available, cannot apply margins
return dialog;
}
Context context = dialog.getContext();
// set dialog to fullscreen
RelativeLayout root = new RelativeLayout( context );
root.setLayoutParams( new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) );
dialog.requestWindowFeature( Window.FEATURE_NO_TITLE );
dialog.setContentView( root );
// set background to get rid of additional margins
window.setBackgroundDrawable( new ColorDrawable( Color.WHITE ) );
// apply left and top margin directly
window.setGravity( Gravity.LEFT | Gravity.TOP );
LayoutParams attributes = window.getAttributes();
attributes.x = marginLeft;
attributes.y = marginTop;
window.setAttributes( attributes );
// set right and bottom margin implicitly by calculating width and height of dialog
Point displaySize = getDisplayDimensions( context );
int width = displaySize.x - marginLeft - marginRight;
int height = displaySize.y - marginTop - marginBottom;
window.setLayout( width, height );
return dialog;
}
Here are the helper methods I used:
@NonNull
public static Point getDisplayDimensions( Context context )
{
WindowManager wm = ( WindowManager ) context.getSystemService( Context.WINDOW_SERVICE );
Display display = wm.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics( metrics );
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
// find out if status bar has already been subtracted from screenHeight
display.getRealMetrics( metrics );
int physicalHeight = metrics.heightPixels;
int statusBarHeight = getStatusBarHeight( context );
int navigationBarHeight = getNavigationBarHeight( context );
int heightDelta = physicalHeight - screenHeight;
if ( heightDelta == 0 || heightDelta == navigationBarHeight )
{
screenHeight -= statusBarHeight;
}
return new Point( screenWidth, screenHeight );
}
public static int getStatusBarHeight( Context context )
{
Resources resources = context.getResources();
int resourceId = resources.getIdentifier( "status_bar_height", "dimen", "android" );
return ( resourceId > 0 ) ? resources.getDimensionPixelSize( resourceId ) : 0;
}
public static int getNavigationBarHeight( Context context )
{
Resources resources = context.getResources();
int resourceId = resources.getIdentifier( "navigation_bar_height", "dimen", "android" );
return ( resourceId > 0 ) ? resources.getDimensionPixelSize( resourceId ) : 0;
}
The helper methods are explained in another of my SO answers.
This Gist contains an extended versions that supports immersve mode too.