lblasa
lblasa

Reputation: 6374

How to set margins to a custom dialog?

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 explicitly WRAP_CONTENT on the layout params.

Basically, the dialog contains a listview whose elements must be scrolled down, when the elements are 1 for example, it doesn't stretch, but when more items are added, then the dialog occupies the entire screen.

Any suggestions? I've trying all possible combinations of possible solutions without achieving satisfactory results

EDIT: Added the dialog layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_margin="50dip"   
    android:orientation="vertical"
    android:layout_gravity="top|center">

    <FrameLayout android:layout_width="fill_parent" android:layout_margin="5dip" android:layout_height="wrap_content">

            <TextView android:layout_width="wrap_content"        android:layout_height="wrap_content" 
                android:layout_gravity="center"
                android:textSize="20sp" android:textColor="@color/black"/>

            <Button android:layout_height="32dip" android:layout_width="32dip" 
                android:id="@+id/guide_dialog_cross_button"
                android:background="@drawable/button_cross_white"/>

        </FrameLayout>


    <ListView android:layout_width="fill_parent" android:layout_height="wrap_content" 
        android:fadingEdge="none"
        android:layout_margin="5dip"/>

    <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:layout_margin="5dip" />

</LinearLayout>

Upvotes: 98

Views: 112964

Answers (18)

DanMan
DanMan

Reputation: 1053

If someone still looking for an elegant way to add margins, you can try this code:

 val dialog = AlertDialog.Builder(requireContext())
        .setView(R.layout.custom_layout)
        .create()
    dialog.window?.apply {
        decorView.setPadding(
            0,
            0,
            0,
            requireContext().resources.getDimensionPixelSize(R.dimen.margin_default)
        )
    }
    dialog.show()

Upvotes: 0

seyed Abolfazl
seyed Abolfazl

Reputation: 70

You can distance your AlertDialog from the parents by removing the margin from width. (Because the AlertDialog is placed in the middle and is separated from the parents by an equal amount.)

Dialog dialog = new Dialog(MainActivity.this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.alertdialog);
dialog.setCancelable(false);

  int device_with = Resources.getSystem().getDisplayMetrics().widthPixels;
  int margin = 40; // dp
  int width = (device_with - DPtoPX(margin));
  int height = ViewPager.LayoutParams.WRAP_CONTENT;
  dialog.getWindow().setLayout(width, height);

dialog.show();

This is DPtoPX(Dip to Pixel) converter method:

private int DPtoPX(int dp){
   return (int) (dp * Resources.getSystem().getDisplayMetrics().density); 
}

Good luck.

Upvotes: 0

Vodet
Vodet

Reputation: 1519

This is the best solution for me

AlertDialog alertDialog = new MaterialAlertDialogBuilder(presenter.getActivity()).setView(view)
                .setBackgroundInsetStart((int) getContext().getResources().getDimension(R.dimen.margin_20))
                .setBackgroundInsetEnd((int) getContext().getResources().getDimension(R.dimen.margin_20)).create();

You can modify the margin start and end and dont use the getWindow().setLayout() because this can lead to some issue

Upvotes: 0

timgo
timgo

Reputation: 455

There is a much easier and cleaner solution than any of the existing answers:

val dialog = AlertDialog.Builder(context)
    .setTitle(title)
    .create()

dialog.setView(view, spacingLeft, spacingTop, spacingRight, spacingBottom)

https://developer.android.com/reference/android/app/AlertDialog#setView(android.view.View,%20int,%20int,%20int,%20int)

Note that AlertDialog.Builder does not have this method, but you have to call it on the dialog directly.

(Setting margins does not work because AlertController overrides LayoutParams when adding the view to the parent FrameLayout)

Upvotes: 1

Anusree Sajeevan
Anusree Sajeevan

Reputation: 11

Step 1. Add the following styles

    <style name="CustomStyle" parent="Theme.MaterialComponents.Light.Dialog">
            <item name="android:windowIsFloating">true</item>
            <item name="android:windowIsTranslucent">false</item>
            <item name="android:windowTranslucentStatus">false</item>
            <item name="android:windowTranslucentNavigation">false</item>
        </style>

Step 2. Extend custom dialog from DialogFragment and override the following

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setStyle(STYLE_NO_TITLE, R.style.CustomStyle)
    }

    override fun onStart() {
        super.onStart()
        val dialog: Dialog? = dialog
        if (dialog != null) {
            val width = ViewGroup.LayoutParams.MATCH_PARENT
            val height = ViewGroup.LayoutParams.MATCH_PARENT
            dialog.window?.setLayout(width, height)
            dialog?.window?.setBackgroundDrawable(InsetDrawable(ColorDrawable(resources.getColor(R.color.transparent, null)), 10, 10, 10, 10))
        }
    }

You will be able to get full screen dialog fragment with margins, without the status bar or overlapping navigation icons.

Upvotes: 1

The Fluffy T Rex
The Fluffy T Rex

Reputation: 600

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>

Upvotes: 8

Amirshayan Nasirimajd
Amirshayan Nasirimajd

Reputation: 11

you could make a new shape drawable resource and set color of it transparent :

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#00000000"/>
</shape>

then you can add these simple lines in your dialog class onCreate method :

getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT,WindowManager.LayoutParams.MATCH_PARENT);  
getWindow().setBackgroundDrawableResource(R.drawable.drawble_resource_you_made_before);

don't forget to put your dialog layout resource background white or any color you want then you could easily by editing your dialog layout resource and customize it :)

Upvotes: 1

Sagar H
Sagar H

Reputation: 5541

If you are creating a custom dialog with the background you can prefer the following code. You can change window property MATCH_PARENT for full screen.

My issue was width of dialog matching to its parent without margin

try following code as per requirement

    Window window = event_dialog.getWindow();
    window.setGravity(Gravity.CENTER);
    WindowManager.LayoutParams wlp = window.getAttributes();
    wlp.width = WindowManager.LayoutParams.MATCH_PARENT;
    wlp.height = WindowManager.LayoutParams.WRAP_CONTENT;
    wlp.flags &= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
    window.setAttributes(wlp);

set these property before dialog.show() OR you can set LEFT,RIGHT,TOP,BOTTOM margin to your dialog by setting margin to your root layout and custom background to its child layout like

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
   <LinearLayout
    android:id="@+id/customLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/card_round_corner"
    android:orientation="vertical">

   </LinearLayout>
</RelativeLayout>

Upvotes: 0

Nanang Fitrianto
Nanang Fitrianto

Reputation: 678

if you extend Dialog Fragment, put this:

override fun onStart() {
        super.onStart()
        if (dialog != null) {
            dialog!!.getWindow()!!.setLayout(Constraints.LayoutParams.MATCH_PARENT, Constraints.LayoutParams.WRAP_CONTENT) // full width dialog
            val back = ColorDrawable(Color.TRANSPARENT)
            val margin = 16
            val inset = InsetDrawable(back, margin)
            dialog!!.window!!.setBackgroundDrawable(inset)
        }
    }

layoutparams is depend on your dialog parent view

Upvotes: 2

Badr Bujbara
Badr Bujbara

Reputation: 8671

One easy way is to set the root layout to transparent background. Then, have its first child have margins or pre set height and width.

Upvotes: 0

Jes&#250;s Barrera
Jes&#250;s Barrera

Reputation: 459

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>

Upvotes: 20

Hitesh Sarsava
Hitesh Sarsava

Reputation: 680

1) change your main parent layout height match_content like below :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="match_content"
    android:layout_margin="50dip"   
    android:orientation="vertical"
    android:layout_gravity="top|center">

2) now add style to your styles.xml

<style name="dialogTheme" parent="Base.Theme.AppCompat.Light.Dialog.Alert"/>

3) now add below code to show dialog :

Dialog dialog = new Dialog(DayActivity.this, R.style.dialogTheme);
dialog.setContentView(R.layout.dialog_custom_layout);
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
dialog.show();

Upvotes: 0

simpleApps
simpleApps

Reputation: 774

I had the same problem and I solved it by setting the window background on an InsetDrawable:

AlertDialog.Builder builder = new AlertDialog.Builder(context);
...
...
AlertDialog dialog = builder.create();

ColorDrawable back = new ColorDrawable(Color.TRANSPARENT);
InsetDrawable inset = new InsetDrawable(back, 20);
dialog.getWindow().setBackgroundDrawable(inset);

dialog.show();

In this case the dialog will appear with a margin of 20 to all edges.

Upvotes: 69

Peter F
Peter F

Reputation: 4289

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.

Upvotes: 4

Teo Inke
Teo Inke

Reputation: 5986

A simple solution that worked for me was to wrap my entire View in another one, and set the margin to which is now the inner View.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_margin="22dp"
        android:orientation="vertical"
        android:layout_width="220dp"
        android:layout_height="wrap_content">

    ... Buttons, TextViews, etc

    </LinearLayout>

</LinearLayout>

Obs: that worked when I wanted margins within my AlertDialog. Not regarding the screen.

Upvotes: 2

Moh Mah
Moh Mah

Reputation: 2055

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

Upvotes: 8

pospi
pospi

Reputation: 3580

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

Upvotes: 145

Nimesh Madhavan
Nimesh Madhavan

Reputation: 6318

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

Upvotes: 21

Related Questions