如何为自定义对话框设置边距?

Posted

技术标签:

【中文标题】如何为自定义对话框设置边距?【英文标题】:How to set margins to a custom dialog? 【发布时间】:2011-09-03 10:53:22 【问题描述】:

有人知道如何为自定义对话框设置边距吗?我问是因为我有一个自定义对话框,但是当显示它时它会拉伸以填充父级,即使我在布局参数上明确设置了 WRAP_CONTENT。

基本上,对话框包含一个listview,其元素必须向下滚动,例如当元素为1时,它不会拉伸,但是当添加更多项目时,对话框会占据整个屏幕。

有什么建议吗?我尝试了所有可能的解决方案组合,但没有取得令人满意的结果

编辑:添加对话框布局

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

    <FrameLayout android:layout_ android:layout_margin="5dip" android:layout_>

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

            <Button android:layout_ android:layout_ 
                android:id="@+id/guide_dialog_cross_button"
                android:background="@drawable/button_cross_white"/>

        </FrameLayout>


    <ListView android:layout_ android:layout_ 
        android:fadingEdge="none"
        android:layout_margin="5dip"/>

    <ImageButton android:layout_ android:layout_
        android:layout_margin="5dip" />

</LinearLayout>

【问题讨论】:

【参考方案1】:

边距不适用于对话框,我想***窗口视图不是支持边距的布局类型。我看过帖子说边距在定义为对话框的样式时会起作用(而不是在***视图元素上),但这似乎也不起作用。

要解决此问题,您需要做的是为 Dialog 背景使用 inset 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>

对话框主视图:

<?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_
    android:layout_
    android:paddingTop="5dp"
    android:paddingBottom="5dp"
    android:paddingLeft="15dp"
    android:paddingRight="15dp"
    android:background="@drawable/dialog_background_inset">

<!-- ...the rest of the layout... -->

您可能还需要将对话框本身的背景颜色设置为透明。像这样添加颜色资源:

<color name="transparent">#00000000</color>

并将对话框的窗口背景颜色设置为此(注意:不能直接指定颜色,eclipse会报错)

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

此样式应作为theme 参数传递给对话框的构造函数,如new Dialog(context, R.style.Dialog);

【讨论】:

如果您在对话框样式中使用 dialog_background_inset 可绘制作为 windowBackground 并且不为对话框布局使用背景,您不必担心在布局中包含额外的填充以允许插图。 @ChrisJD 我无法让它工作。无论如何,pospi 解决方案正在发挥作用。有时真的很奇怪,Android 需要多少奇怪的代码来实现非常简单的事情。 @pospi 你知道如何在对话框内容之外单击时取消它吗?因为它无法使用您的解决方案。 有效,但正面按钮出现在对话框外,看起来很奇怪 猜猜这是更好的解决方案***.com/a/48991360/1621111【参考方案2】:

我遇到了同样的问题,我通过在 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();

在这种情况下,对话框将显示为所有边缘的边距为 20。

【讨论】:

它适用于较新的 API,但当我在 API 16 上进行测试时,它在 AlertDialog 周围显示黑色边框。 这也适用于DialogFragment,甚至适用于负值(原文如此!):new InsetDrawable(back, 16, -8, 16, -8);。太好了!【参考方案3】:

边距似乎不适用于对话框的自定义布局,但填充有效。尝试在***线性布局上设置填充。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_
    android:layout_
    android:paddingLeft="4dp"
    android:paddingRight="4dp" >

【讨论】:

【参考方案4】:

正如@simpleApps 和@pospi 所指出的,您需要在Dialog 的backgroundDrawable 中添加插图。如果您使用的是自定义对话框,则可以尝试使用 xml 中定义的可绘制对象

dialog?.window?.setBackgroundDrawableResource(R.drawable.background_dialog)

其中 R.drawable.background_dialog 定义为

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

【讨论】:

【参考方案5】:

可以这样解决:

dialog.getWindow().getAttributes().height = 
           (int) (getDeviceMetrics(context).heightPixels*0.8);

`getDeviceMetrics 方法:

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;

【讨论】:

只有在 dialog.show(); 之后设置它才对我有用,就像这样:WindowManager.LayoutParams params = dialog.getWindow().getAttributes(); params.height = (int) (Utils.getDeviceMetrics(LoginActivity.this).height * 0.8); dialog.getWindow().setAttributes(params); 这是关于对话框高度而不是边距【参考方案6】:

这是一种直接的、程序化的方式来设置我的对话框的位置和大小以及边距。

我通过在onCreateDialog 方法中应用DialogFragment 来测试我的方法:

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;

这是将边距应用于对话框的方法:

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;

以下是我使用的辅助方法:

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

在我的另一个SO answers 中解释了辅助方法。

这个Gist 包含一个扩展版本,也支持沉浸模式。

【讨论】:

【参考方案7】:

我在使用其他解决方案时遇到了问题,因为“确定”和“取消”按钮超出了屏幕,看起来很奇怪。相反,我使用了android:windowMinWidthMinor & android:windowMinWidthMajor,它看起来更好,而且还需要更少的代码。 Java / Kotlin 不需要任何东西。

这就是我所做的一切:

1) 只使用一个背景可绘制对象(我叫我的 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) 在布局中设置背景:

<?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_
    android:layout_
    android:background="@drawable/dialog_box">

</androidx.constraintlayout.widget.ConstraintLayout>

3) 设置样式:

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

【讨论】:

windowMinWidthMinor 有效,看起来像默认宽度警报对话框 windowMinWidthMinor 真的是我想要的,谢谢。【参考方案8】:

一个对我有用的简单解决方案是将我的整个 View 包裹在另一个 View 中,并将边距设置为现在是内部 View。

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

    <LinearLayout
        android:layout_margin="22dp"
        android:orientation="vertical"
        android:layout_
        android:layout_>

    ... Buttons, TextViews, etc

    </LinearLayout>

</LinearLayout>

Obs:当我想要我的 AlertDialog 中留出边距时,这很有效。与屏幕无关。

【讨论】:

所以您可以只添加填充而不是将其包装在另一个布局中。 根视图本身的填充不起作用。请先测试代码,然后再假设它是错误的并投反对票。 不需要其他布局,&lt;android.support.constraint.ConstraintLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:layout_marginStart="16dp"'【参考方案9】:

如果您扩展 Dialog Fragment,请输入:

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 取决于您的对话框父视图

【讨论】:

【参考方案10】:

你可以制作一个新的图形可绘制资源并将其颜色设置为透明:

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

然后您可以在对话框类的 onCreate 方法中添加这些简单的行:

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

不要忘记将您的对话框布局资源背景设置为白色或您想要的任何颜色,然后您可以轻松地编辑您的对话框布局资源并对其进行自定义:)

【讨论】:

【参考方案11】:

步骤 1. 添加以下样式

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

步骤 2. 从 DialogFragment 扩展自定义对话框并覆盖以下内容

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

您将能够获得带有边距的全屏对话框片段,没有状态栏或重叠的导航图标。

【讨论】:

【参考方案12】:

有一个比任何现有答案都更简单、更清洁的解决方案:

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)

注意AlertDialog.Builder确实没有有这个方法,但是你必须直接在对话框中调用它。

(设置边距不起作用,因为在将视图添加到父 FrameLayout 时,AlertController 会覆盖 LayoutParams)

【讨论】:

又好又简单,我用 TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.displayMetrics).toInt()【参考方案13】:

1) 更改您的主要父布局高度match_content,如下所示:

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

2) 现在将样式添加到您的styles.xml

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

3) 现在添加以下代码以显示对话框:

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

【讨论】:

【参考方案14】:

一种简单的方法是将根布局设置为透明背景。然后,让它的第一个孩子有边距或预设的高度和宽度。

【讨论】:

【参考方案15】:

如果您要创建带有背景的自定义对话框,您可以选择以下代码。 您可以将窗口属性MATCH_PARENT 更改为全屏。

我的问题是对话框的宽度与其父级匹配,没有边距

根据要求尝试以下代码

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

dialog.show() 之前设置这些属性您可以通过将margin 设置为root 布局并将custom background 设置为其子布局,将LEFT,RIGHT,TOP,BOTTOM 设置为对话框的边距,例如 p>

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

   </LinearLayout>
</RelativeLayout>

【讨论】:

【参考方案16】:

这对我来说是最好的解决方案

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

您可以修改边距开始和结束,不要使用getWindow().setLayout(),因为这可能会导致一些问题

【讨论】:

以上是关于如何为自定义对话框设置边距?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Theme.Holo.DialogWhenLarge 设置为自定义大小、位置、边距等?

加载 WebView 页面时如何为警报对话框设置不同的标题?

如何为 Android 中的日期和时间选择器对话框设置的特定时间和日期设置通知

如何为特定的星期几设置重复通知?

如何为 gps 使用特定对话框?

如何创建传递参数的自定义Facebook共享对话框?