在 Android 中,如何以编程方式在 dp 中设置边距?

Posted

技术标签:

【中文标题】在 Android 中,如何以编程方式在 dp 中设置边距?【英文标题】:In Android, how do I set margins in dp programmatically? 【发布时间】:2012-09-25 13:08:28 【问题描述】:

在this、this 和this 线程中,我试图找到有关如何在单个视图上设置边距的答案。但是,我想知道是否没有更简单的方法。我将解释为什么我不想使用这种方法:

我有一个扩展 Button 的自定义 Button。如果背景设置为默认背景以外的其他内容(通过调用setBackgroundResource(int id)setBackgroundDrawable(Drawable d)),我希望边距为0。如果我这样称呼:

public void setBackgroundToDefault() 
    backgroundIsDefault = true;
    super.setBackgroundResource(android.R.drawable.btn_default);
    // Set margins somehow

我希望将边距重置为 -3dp(我已经阅读了 here 如何从像素转换为 dp,所以一旦我知道如何以 px 为单位设置边距,我就可以自己管理转换)。但由于这是在CustomButton 类中调用的,因此父级可以从 LinearLayout 到 TableLayout 不等,我宁愿不让他得到他的父级并检查该父级的实例。我想,这也将是相当低效的。

另外,当调用(使用 LayoutParams)parentLayout.addView(myCustomButton, newParams) 时,我不知道这是否会将其添加到正确的位置(但是没有尝试过),比如说一排五个的中间按钮。

问题:除了使用 LayoutParams 之外,还有没有更简单的方法以编程方式设置单个 Button 的边距

编辑:我知道 LayoutParams 方式,但我想要一个避免处理每种不同容器类型的解决方案:

ViewGroup.LayoutParams p = this.getLayoutParams();
    if (p instanceof LinearLayout.LayoutParams) 
        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)p;
        if (_default) lp.setMargins(mc.oml, mc.omt, mc.omr, mc.omb);
        else lp.setMargins(mc.ml, mc.mt, mc.mr, mc.mb);
        this.setLayoutParams(lp);
    
    else if (p instanceof RelativeLayout.LayoutParams) 
        RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)p;
        if (_default) lp.setMargins(mc.oml, mc.omt, mc.omr, mc.omb);
        else lp.setMargins(mc.ml, mc.mt, mc.mr, mc.mb);
        this.setLayoutParams(lp);
    
    else if (p instanceof TableRow.LayoutParams) 
        TableRow.LayoutParams lp = (TableRow.LayoutParams)p;
        if (_default) lp.setMargins(mc.oml, mc.omt, mc.omr, mc.omb);
        else lp.setMargins(mc.ml, mc.mt, mc.mr, mc.mb);
        this.setLayoutParams(lp);
    

因为this.getLayoutParams();返回一个ViewGroup.LayoutParams,它没有topMarginbottomMarginleftMarginrightMargin的属性。 您看到的 mc 实例只是一个 MarginContainer,其中包含偏移 (-3dp) 边距和 (oml, omr, omt, omb) 和原始边距 (ml, mr, mt, mb)。

【问题讨论】:

【参考方案1】:

您应该使用LayoutParams 来设置您的按钮边距:

LayoutParams params = new LayoutParams(
        LayoutParams.WRAP_CONTENT,      
        LayoutParams.WRAP_CONTENT
);
params.setMargins(left, top, right, bottom);
yourbutton.setLayoutParams(params);

根据您使用的布局,您应该使用RelativeLayout.LayoutParamsLinearLayout.LayoutParams

要将您的 dp 测量值转换为像素,请尝试以下操作:

Resources r = mContext.getResources();
int px = (int) TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        yourdpmeasure, 
        r.getDisplayMetrics()
);

【讨论】:

我应该从哪个包中导入特定的 LayoutParams? setMargins 使用 px,你将使用 dp,我的转换是正确的:dp -> px 设置正确的边距值。 @ChristiaandeJong RelativeLayout.LayoutParams 这取决于您当前的布局。如果您在 LinearLayout 中,请使用 LinearLayout.LayoutParams。否则为RelativeLayout.LayoutParams 您应该导入 layoutParams ,这是您的父布局 ex。 并且您正在使用网格布局。然后,你需要使用 relativelayout.layoutparams【参考方案2】:

LayoutParams - 不工作! ! !

需要使用类型:MarginLayoutParams

MarginLayoutParams params = (MarginLayoutParams) vector8.getLayoutParams();
params.width = 200; params.leftMargin = 100; params.topMargin = 200;

MarginLayoutParams 的代码示例:

http://www.codota.com/android/classes/android.view.ViewGroup.MarginLayoutParams

【讨论】:

正确,但无需重新设置,更改的参数会自动反映。因此,您可以删除该行:vector8.setLayoutParams(params); LayaoutParams 通常在设置边距时会造成混乱...所以这个 MarginLayoutParams 非常有用。谢谢 你需要在边距更改后设置布局参数(参数) 我今天发现 MarginLayoutParams 是新课程#谢谢。 不适用于Button 查看:ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) button.getLayoutParams() 返回null【参考方案3】:

layout_margin 是视图子告诉其父视图的约束。然而,选择是否允许保证金是父母的角色。基本上通过设置 android:layout_margin="10dp",孩子请求父视图组分配比其实际大小10dp 大的空间。 (另一方面,padding="10dp" 表示子视图会将自己的内容缩小 10dp。)

因此,并非所有 ViewGroup 都尊重边距。最臭名昭著的例子是列表视图,其中项目的边距被忽略。在调用 setMargin() 到 LayoutParam 之前,您应该始终确保当前视图位于支持边距(例如 LinearLayouot 或 RelativeLayout)的 ViewGroup 中,并将 getLayoutParams() 的结果转换为您想要的特定 LayoutParams。 (ViewGroup.LayoutParams 甚至没有setMargins() 方法!)

下面的函数应该可以解决问题。 但请确保将 RelativeLayout 替换为父视图的类型。

private void setMargin(int marginInPx) 
    RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) getLayoutParams();
    lp.setMargins(marginInPx,marginInPx, marginInPx, marginInPx);
    setLayoutParams(lp);

【讨论】:

【参考方案4】:

这个方法可以让你在DP

中设置Margin
public void setMargin(Context con,ViewGroup.LayoutParams params,int dp) 

        final float scale = con.getResources().getDisplayMetrics().density;
        // convert the DP into pixel
        int pixel =  (int)(dp * scale + 0.5f); 

        ViewGroup.MarginLayoutParams s =(ViewGroup.MarginLayoutParams)params;
        s.setMargins(pixel,pixel,pixel,pixel);

        yourView.setLayoutParams(params);

更新

您可以更改适合您需要的参数。

【讨论】:

【参考方案5】:
int sizeInDP = 16;

int marginInDp = (int) TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, sizeInDP, getResources()
                    .getDisplayMetrics());

然后

layoutParams = myView.getLayoutParams()
layoutParams.setMargins(marginInDp, marginInDp, marginInDp, marginInDp);
myView.setLayoutParams(layoutParams);

或者

LayoutParams layoutParams = new LayoutParams...
layoutParams.setMargins(marginInDp, marginInDp, marginInDp, marginInDp);
myView.setLayoutParams(layoutParams);

【讨论】:

最容易理解和应用的答案 什么是getResources()?【参考方案6】:

有史以来最好的方式:

private void setMargins (View view, int left, int top, int right, int bottom) 
    if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) 
        ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
        p.setMargins(left, top, right, bottom);
        view.requestLayout();
    

如何调用方法:

setMargins(mImageView, 50, 50, 50, 50);

希望这会对你有所帮助。

【讨论】:

当我 设置 setMargins(holder.vCenter, 0, 20, 0,0); 时遇到问题上面的参数有错吗? 很棒的完美答案!!谢谢!! 我们为什么需要requestLayout() 谢谢,这个答案给了我一个使用 mys 的想法。【参考方案7】:

以下是最新更新的一体化答案:

第 1 步,更新边距

基本的想法是获取margin然后更新它。更新将自动应用,您无需重新设置。要获取布局参数,只需调用此方法即可:

LayoutParams layoutParams = (LayoutParams) yourView.findViewById(R.id.THE_ID).getLayoutParams();

LayoutParams 来自您的视图布局。如果视图来自线性布局,则需要导入LinearLayout.LayoutParams。如果使用相对布局,导入LinearLayout.LayoutParams

现在,如果您使用Layout_marginLeftRight等设置边距,则需要以这种方式更新边距

layoutParams.setMargins(left, top, right, bottom);

如果你使用新的layout_marginStart设置边距,你需要这样更新边距

layoutParams.setMarginStart(start);
layoutParams.setMarginEnd(end);

第 2 步,以 dp 更新边距

以上两种更新边距的方法都是以像素为单位更新。您需要将 dp 转换为像素。

float dpRatio = context.getResources().getDisplayMetrics().density;
int pixelForDp = (int)dpValue * dpRatio;

现在把计算出来的值放到上面的边距更新函数中,你应该都设置好了

【讨论】:

【参考方案8】:

像今天一样,最好的可能是使用Paris,AirBnB 提供的一个库。

然后可以像这样应用样式:

Paris.style(myView).apply(R.style.MyStyle);

它还支持使用注释的自定义视图(如果您扩展视图):

@Styleable and @Style

【讨论】:

【参考方案9】:

使用该方法设置dp中的margin

private void setMargins (View view, int left, int top, int right, int bottom) 
    if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) 
        ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) view.getLayoutParams();

        final float scale = getBaseContext().getResources().getDisplayMetrics().density;
        // convert the DP into pixel
        int l =  (int)(left * scale + 0.5f);
        int r =  (int)(right * scale + 0.5f);
        int t =  (int)(top * scale + 0.5f);
        int b =  (int)(bottom * scale + 0.5f);

        p.setMargins(l, t, r, b);
        view.requestLayout();
    

调用方法:

setMargins(linearLayout,5,0,5,0);

【讨论】:

很简单!。谢谢【参考方案10】:

对于快速的单行设置使用

((LayoutParams) cvHolder.getLayoutParams()).setMargins(0, 0, 0, 0);

但要注意 LayoutParams 的任何错误使用,因为这将没有 if statment instance chech

【讨论】:

【参考方案11】:

当您在自定义视图中时,您可以使用getDimensionPixelSize(R.dimen.dimen_value),在我的例子中,我在init 方法创建的LayoutParams 中添加了边距。

在 Kotlin 中

init 
    LayoutInflater.from(context).inflate(R.layout.my_layout, this, true)
    layoutParams = LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply 
    val margin = resources.getDimensionPixelSize(R.dimen.dimen_value)
    setMargins(0, margin, 0, margin)

在 Java 中:

public class CustomView extends LinearLayout 

    //..other constructors

    public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) 
        super(context, attrs, defStyleAttr);
        init();
    

    private void init() 
        LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        int margin = getResources().getDimensionPixelSize(R.dimen.spacing_dime);
        params.setMargins(0, margin, 0, margin);
        setLayoutParams(params);
    

【讨论】:

【参考方案12】:
((FrameLayout.LayoutParams) linearLayout.getLayoutParams()).setMargins(450, 20, 0, 250);
        linearLayout.setBackgroundResource(R.drawable.smartlight_background);

我不得不将我的线性布局转换为FrameLayout,因为它继承自它并在那里设置边距,因此活动只出现在屏幕的一部分上,并且背景与setContentView 中的原始布局参数不同。

LinearLayout linearLayout = (LinearLayout) findViewById(R.id.activity);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(WindowManager.LayoutParams.FILL_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
linearLayout.setBackgroundColor(getResources().getColor(R.color.full_white));
setContentView(linearLayout,layoutParams);

其他人都无法使用相同的活动并根据从不同菜单打开活动来更改边距! setLayoutParams 从来没有为我工作过——设备每次都会崩溃。尽管这些是硬编码的数字 - 这只是用于演示目的的代码示例。

【讨论】:

【参考方案13】:

为那些可能觉得很方便的人创建了一个 Kotlin 扩展函数。

确保传入像素而不是 dp。快乐编码:)

fun View.addLayoutMargins(left: Int? = null, top: Int? = null,
                      right: Int? = null, bottom: Int? = null) 
    this.layoutParams = ViewGroup.MarginLayoutParams(this.layoutParams)
            .apply 
                left?.let  leftMargin = it 
                top?.let  topMargin = it 
                right?.let  rightMargin = it 
                bottom?.let  bottomMargin = it 
            

【讨论】:

android.view.ViewGroup$MarginLayoutParams 不能转换为 android.widget.RelativeLayout$LayoutParams。 :(【参考方案14】:

在我的示例中,我以编程方式将 ImageView 添加到 LinearLayout。我已将顶部和底部边距设置为 ImagerView。然后将 ImageView 添加到 LinearLayout。



        ImageView imageView = new ImageView(mContext);
        imageView.setImageBitmap(bitmap);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT
        );
        params.setMargins(0, 20, 0, 40);
        imageView.setLayoutParams(params);
        linearLayout.addView(imageView);

【讨论】:

【参考方案15】:

您可以使用此方法,并根据您的设备将静态尺寸设置为 20 来转换

 public static int dpToPx(int dp) 
      
          float scale = context.getResources().getDisplayMetrics().density;
       return (int) (dp * scale + 0.5f);
  

【讨论】:

【参考方案16】:

您可以使用ViewGroup.MarginLayoutParams设置宽度、高度和边距

ViewGroup.MarginLayoutParams marginLayoutParams = new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
marginLayoutParams.setMargins(0,16,0,16);
linearLayout.setLayoutParams(marginLayoutParams);

setMargins(); 方法分别接受左、上、右、下的值。顺时针!,从左边开始。

【讨论】:

【参考方案17】:

在 Kotlin 中它看起来像这样:

val layoutParams = (yourView?.layoutParams as? MarginLayoutParams)
layoutParams?.setMargins(40, 40, 40, 40)
yourView?.layoutParams = layoutParams

【讨论】:

这没有回答问题,因为 setMargins 方法只接受以像素为单位的值,而不接受用户要求的 dp。【参考方案18】:

如果你想为你的 TextView 添加一个边距,你必须使用 LayoutParams:

val params =  LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT)
params.setMargins(int left, int top, int right, int bottom)
your_view.layoutParams = params

LayoutParams 可以是任何布局,如相对、线性、视图或视图组。根据需要选择 LayoutParams。谢谢

【讨论】:

操作要求边距 我提到了内边距和边距。我想你误会了。我希望你能正确阅读我的整个答案! @anshsachdeva 是的,我的错。自从我发表评论以来已经 2 天了,所以我无法更改我的 -1。请对您的答案进行编辑以突出显示实际解决方案,我会更改它:) @anshsachdeva,我已经更新了我的答案。让我知道它是否有帮助。谢谢【参考方案19】:

简单的 Kotlin 扩展解决方案

独立设置所有/任何一侧:

fun View.setMargin(left: Int? = null, top: Int? = null, right: Int? = null, bottom: Int? = null) 
    val params = (layoutParams as? MarginLayoutParams)
    params?.setMargins(
            left ?: params.leftMargin,
            top ?: params.topMargin,
            right ?: params.rightMargin,
            bottom ?: params.bottomMargin)
    layoutParams = params


myView.setMargin(10, 5, 10, 5)
// or just any subset
myView.setMargin(right = 10, bottom = 5)

直接引用一个资源值:

fun View.setMarginRes(@DimenRes left: Int? = null, @DimenRes top: Int? = null, @DimenRes right: Int? = null, @DimenRes bottom: Int? = null) 
    setMargin(
            if (left == null) null else resources.getDimensionPixelSize(left),
            if (top == null) null else resources.getDimensionPixelSize(top),
            if (right == null) null else resources.getDimensionPixelSize(right),
            if (bottom == null) null else resources.getDimensionPixelSize(bottom),
    )


myView.setMarginRes(top = R.dimen.my_margin_res)

直接将所有边设置为属性:

var View.margin: Int
    get() = throw UnsupportedOperationException("No getter for property")
    set(@Px margin) = setMargin(margin, margin, margin, margin)
   
myView.margin = 10 // px

// or as res
var View.marginRes: Int
    get() = throw UnsupportedOperationException("No getter for property")
    set(@DimenRes marginRes) 
        margin = resources.getDimensionPixelSize(marginRes)
    

myView.marginRes = R.dimen.my_margin_res

要直接设置特定的边,你可以像这样创建一个属性扩展:

var View.leftMargin
    get() = marginLeft
    set(@Px leftMargin) = setMargin(left = leftMargin)

var View.leftMarginRes: Int
    get() = throw UnsupportedOperationException("No getter for property")
    set(@DimenRes leftMarginRes) 
        leftMargin = resources.getDimensionPixelSize(leftMarginRes)
    

这也允许您制作horizontalvertical 变体:

var View.horizontalMargin
    get() = throw UnsupportedOperationException("No getter for property")
    set(@Px horizontalMargin) = setMargin(left = horizontalMargin, right = horizontalMargin)

var View.horizontalMarginRes: Int
    get() = throw UnsupportedOperationException("No getter for property")
    set(@DimenRes horizontalMarginRes) 
        horizontalMargin = resources.getDimensionPixelSize(horizontalMarginRes)
    

注意:如果未能设置边距,您可能会在渲染之前过早,即params == null。尝试使用 myView.post margin = 10 包装修改

【讨论】:

【参考方案20】:

这就是我在kotlin所做的事情

fun View.setTopMargin(@DimenRes dimensionResId: Int) 
    (layoutParams as ViewGroup.MarginLayoutParams).topMargin = resources.getDimension(dimensionResId).toInt()

【讨论】:

这确实是一个干净的解决方案。它帮助了我。【参考方案21】:

有兴趣的人可以使用 DP 工作 utils 函数:

public static void setMargins(Context context, View view, int left, int top, int right, int bottom) 
    int marginLeft = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, left, context.getResources().getDisplayMetrics());
    int marginTop = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, top, context.getResources().getDisplayMetrics());
    int marginRight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, right, context.getResources().getDisplayMetrics());
    int marginBottom = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, bottom, context.getResources().getDisplayMetrics());

    if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) 
        ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
        p.setMargins(marginLeft, marginTop, marginRight, marginBottom);
        view.requestLayout();
    

【讨论】:

【参考方案22】:

根据其他答案,我制作了一个通用扩展函数,它可以识别您的父母并相应地使用参数:

//takes margin values as integer , eg for 12dp top , you will pass 12
fun View?.setMarginFromConstant(mLeft:Int, mTop:Int, mRight:Int, mBottom:Int)
    this?.apply 
        val left = context?.dpToPixel(mLeft)?:0
        val top = context?.dpToPixel(mTop)?:0
        val right = context?.dpToPixel(mRight)?:0
        val bottom = context?.dpToPixel(mBottom)?:0
        when (val params = this.layoutParams) 
            is ConstraintLayout.LayoutParams -> 
                params.marginStart = left
                params.marginEnd = right
                params.topMargin = top
                params.bottomMargin = bottom
            
            is FrameLayout.LayoutParams -> 
                params.marginStart = left
                params.marginEnd = right
                params.topMargin = top
                params.bottomMargin = bottom
            
            is RecyclerView.LayoutParams -> 
                params.marginStart = left
                params.marginEnd = right
                params.topMargin = top
                params.bottomMargin = bottom
            
        
    


fun Context.dpToPixel(dp: Int): Int =
    (dp * applicationContext.resources.displayMetrics.density).toInt()

您也可以添加对其他父视图组的支持

【讨论】:

【参考方案23】:

使用Android KTX,您可以执行以下操作:

yourView.updateLayoutParams<ViewGroup.MarginLayoutParams> 
   setMargins(0, 0, 0, 0)

【讨论】:

【参考方案24】:

使用此方法可以正确设置dp:

public int dpFormat(int dp) 
    DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
    return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));

然后调用

setMargins(dpFormat(15), dpFormat(15), dpFormat(15), dpFormat(15));

【讨论】:

以上是关于在 Android 中,如何以编程方式在 dp 中设置边距?的主要内容,如果未能解决你的问题,请参考以下文章

Android:以编程方式覆盖 Button minheight

以编程方式调整TextView的大小

如何以编程方式在 Android 中重置 Google 广告 ID?

如何以编程方式在 Android 设备中获取设备 (AOSP) 内部版本号?

如何在android中以编程方式从通知栏中删除通知?

如何以编程方式在 Android 中调整麦克风音量