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

时间:2012-10-04 13:22:23

标签: android layout button margin

thisthisthis主题中,我试图找到关于如何在单个视图上设置边距的答案。但是,我想知道是否有更简单的方法。我将解释为什么我宁愿不想使用这种方法:

我有一个扩展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之外,还有更简单的方法以编程方式设置单个按钮的边距吗?

编辑:我知道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)。

22 个答案:

答案 0 :(得分:686)

您应该使用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()
);

答案 1 :(得分:192)

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

答案 2 :(得分:98)

最佳方式:

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

希望这会对你有所帮助。

答案 3 :(得分:28)

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

答案 4 :(得分:7)

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

答案 5 :(得分:7)

此方法可让您在 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);
}

<强>更新

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

答案 6 :(得分:2)

在自定义视图中时,可以使用getDimensionPixelSize(R.dimen.dimen_value),在我的情况下,我在通过init方法创建的LayoutParams中添加了边距。

在科特林

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

答案 7 :(得分:2)

简单的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 }

包装修改

答案 8 :(得分:2)

在Kotlin中,它将如下所示:

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

答案 9 :(得分:1)

使用单行快速设置

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

但是要认真对待LayoutParams的任何错误用法,因为这不会if语句实例的出现

答案 10 :(得分:1)

使用 DP 的实用工具函数供有兴趣的人使用:

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

答案 11 :(得分:1)

我在kotlin中的工作方式

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

答案 12 :(得分:0)

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

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

答案 13 :(得分:0)

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

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

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

答案 14 :(得分:0)

您必须致电

setPadding(int left, int top, int right, int bottom)

像这样: your_view.setPadding(0,16,0,0)

您要使用的只是吸气剂。

Android Studio显示了padding...()在Java中的实际含义:

padding example 该图像显示它仅调用getPadding...()

如果要在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

答案 15 :(得分:0)

已更新:

就像您以前使用ViewGroup.LayoutParams设置布局宽度和高度的方式一样

您可以使用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();分别接受left,top,right和bottom的值。从左开始顺时针!!

答案 16 :(得分:0)

您可以使用此方法,并放置20个静态维度,它会根据您的设备进行转换

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

答案 17 :(得分:0)

在我的示例中,我以编程方式将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);

答案 18 :(得分:0)

为可能会方便使用的人创建了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 }
            }
}

答案 19 :(得分:0)

const uniques = [...new Set(myArray.filter(e => e))];

我必须将我的模型继承自linearLayout,并将其投放到((FrameLayout.LayoutParams) linearLayout.getLayoutParams()).setMargins(450, 20, 0, 250); linearLayout.setBackgroundResource(R.drawable.smartlight_background); 上,并在此处设置边距,以便活动仅显示在屏幕的一部分上,并且背景与{{ 1}}。

FrameLayout

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

答案 20 :(得分:0)

使用此方法在dp中设置边距

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

答案 21 :(得分:0)

就像今天一样,最好的方法是使用AirBnB提供的Paris库。

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

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

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

@Styleable and @Style