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

ste*_*ong 376 layout android margin button

这个,这个这个线程我试图找到如何在单个视图上设置边距的答案.但是,我想知道是否有更简单的方法.我会解释为什么我宁愿不想使用这种方法:

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

public void setBackgroundToDefault() {
    backgroundIsDefault = true;
    super.setBackgroundResource(android.R.drawable.btn_default);
    // Set margins somehow
}
Run Code Online (Sandbox Code Playgroud)

我希望边距重置为-3dp(我已经在这里阅读如何从像素转换为dp,所以一旦我知道如何在px中设置边距,我就可以自己管理转换).但是因为这是在CustomButton类中调用的,所以父级可以从LinearLayout变为TableLayout,而我宁愿不让他得到他的父级并检查该父级的实例.我想,这也将是非常无形的.

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

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

编辑:我知道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);
    }
}
Run Code Online (Sandbox Code Playgroud)

由于this.getLayoutParams();回报ViewGroup.LayoutParams,不具有的属性topMargin,bottomMargin,leftMargin,rightMargin.您看到的mc实例只MarginContainer包含偏移(-3dp)边距和(oml,omr,omt,omb)和原始边距(ml,mr,mt,mb).

thr*_*n19 745

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

LayoutParams params = new LayoutParams(
        LayoutParams.WRAP_CONTENT,      
        LayoutParams.WRAP_CONTENT
);
params.setMargins(left, top, right, bottom);
yourbutton.setLayoutParams(params);
Run Code Online (Sandbox Code Playgroud)

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

要将dp度量转换为像素,请尝试以下操作:

Resources r = mContext.getResources();
int px = (int) TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        yourdpmeasure, 
        r.getDisplayMetrics()
);
Run Code Online (Sandbox Code Playgroud)

  • 我应该从哪个包导入特定的LayoutParams? (142认同)
  • 这取决于您当前的布局.如果您在LinearLayout中,请使用LinearLayout.LayoutParams.否则为RelativeLayout.LayoutParams (13认同)
  • setMargins使用了px,你将使用dp,我的转换是正确的:dp - > px来设置正确的边距值. (7认同)
  • @ChristiaandeJong RelativeLayout.LayoutParams (6认同)
  • 你应该导入作为父布局ex的layoutParams.<linearlayout> <relativelayout> <gridlayout>,您正在使用网格布局.那么,你需要使用relativelayout.layoutparams (5认同)
  • @stoefln为什么选择RelativeLayout.LayoutParams而不是LinearLayout.LayoutParams? (2认同)

小智 208

LayoutParams - 不工作!!!

需要使用的类型:MarginLayoutParams

MarginLayoutParams params = (MarginLayoutParams) vector8.getLayoutParams();
params.width = 200; params.leftMargin = 100; params.topMargin = 200;
Run Code Online (Sandbox Code Playgroud)

MarginLayoutParams的代码示例:

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

  • 正确,但无需将其设置回来,更改的参数会自动反映出来.因此,您可以删除该行:vector8.setLayoutParams(params); (18认同)
  • 在变化结束后你需要setLayoutParams(params) (3认同)
  • 不适用于 `Button` 视图:`ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) button.getLayoutParams()` 返回 `null` (2认同)

Hir*_*tel 111

最好的方式:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

如何调用方法:

setMargins(mImageView, 50, 50, 50, 50);
Run Code Online (Sandbox Code Playgroud)

希望这会帮助你.

  • 为什么我们需要`requestLayout()`? (5认同)
  • 它的工作完全谢谢你. (4认同)

Phi*_*hil 50

使用Android KTX,您可以执行类似的操作:

yourView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
   setMargins(0, 0, 0, 0)
}
Run Code Online (Sandbox Code Playgroud)


sag*_*its 31

int sizeInDP = 16;

int marginInDp = (int) TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, sizeInDP, getResources()
                    .getDisplayMetrics());
Run Code Online (Sandbox Code Playgroud)

然后

layoutParams = myView.getLayoutParams()
layoutParams.setMargins(marginInDp, marginInDp, marginInDp, marginInDp);
myView.setLayoutParams(layoutParams);
Run Code Online (Sandbox Code Playgroud)

要么

LayoutParams layoutParams = new LayoutParams...
layoutParams.setMargins(marginInDp, marginInDp, marginInDp, marginInDp);
myView.setLayoutParams(layoutParams);
Run Code Online (Sandbox Code Playgroud)

  • 恕我直言,这应该是公认的答案。 (2认同)

Fan*_*ing 12

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

第1步,更新保证金

基本的想法是获得保证金,然后更新它.更新将自动应用,您无需将其重新设置.要获取布局参数,只需调用此方法:

LayoutParams layoutParams = (LayoutParams) yourView.findViewById(R.id.THE_ID).getLayoutParams();
Run Code Online (Sandbox Code Playgroud)

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

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

layoutParams.setMargins(left, top, right, bottom);
Run Code Online (Sandbox Code Playgroud)

如果使用new设置保证金layout_marginStart,则需要以这种方式更新保证金

layoutParams.setMarginStart(start);
layoutParams.setMarginEnd(end);
Run Code Online (Sandbox Code Playgroud)

步骤2,更新dp中的保证金

更新上述边距的所有两种方式都是以像素更新.您需要将dp转换为像素.

float dpRatio = context.getResources().getDisplayMetrics().density;
int pixelForDp = (int)dpValue * dpRatio;
Run Code Online (Sandbox Code Playgroud)

现在将计算值放到上面的边际更新函数中,您应该全部设置


Mor*_*zov 12

在 Kotlin 中,它看起来像这样:

val layoutParams = (yourView?.layoutParams as? MarginLayoutParams)
layoutParams?.setMargins(40, 40, 40, 40)
yourView?.layoutParams = layoutParams
Run Code Online (Sandbox Code Playgroud)

  • 这并不能回答问题,因为 setMargins 方法仅接受以像素为单位的值,而不接受用户所要求的 dp 值。 (3认同)

Ian*_*ong 9

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

因此,并非所有ViewGroup都尊重保证金.最臭名昭着的例子是listview,其中项目的边距被忽略.在调用setMargin()LayoutParam 之前,应始终确保当前视图位于支持边距的ViewGroup(例如LinearLayouot或RelativeLayout)中,并将结果转换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);
}
Run Code Online (Sandbox Code Playgroud)


Sha*_*aon 9

通过 Kotlin,您可以使用View.updateLayoutParams扩展函数:

yourView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
    setMargins(15,15,15,15)
}

// or

yourView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
    topMargin = 15
}
Run Code Online (Sandbox Code Playgroud)


nef*_*tou 8

此方法可让您在DP中设置保证金

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);
}
Run Code Online (Sandbox Code Playgroud)

UPDATE

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


Gib*_*olt 7

简单的 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)
Run Code Online (Sandbox Code Playgroud)

直接引用一个资源值:

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)
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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

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)
    }
Run Code Online (Sandbox Code Playgroud)

这也允许您制作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)
    }
Run Code Online (Sandbox Code Playgroud)

注意:如果边距设置失败,您可能在渲染之前过早,这意味着params == null. 尝试用myView.post{ margin = 10 }


小智 6

您可以使用此方法并放置静态尺寸,例如 20,它会根据您的设备进行转换

 public static int dpToPx(int dp) 
      {
          float scale = context.getResources().getDisplayMetrics().density;
       return (int) (dp * scale + 0.5f);
  }
Run Code Online (Sandbox Code Playgroud)


Saa*_*yem 6

如果你想为 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
Run Code Online (Sandbox Code Playgroud)

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


Tas*_*eem 5

那我是怎么做的 kotlin

fun View.setTopMargin(@DimenRes dimensionResId: Int) {
    (layoutParams as ViewGroup.MarginLayoutParams).topMargin = resources.getDimension(dimensionResId).toInt()
}
Run Code Online (Sandbox Code Playgroud)