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

我有一个自定义按钮扩展按钮。如果背景被设置为默认背景以外的东西(通过调用setBackgroundResource(int id)或setBackgroundDrawable(Drawable d)),我希望边缘为0。如果我调用这个:

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

我希望边距重置为-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);
    }
}

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


当前回答

使用芬兰湾的科特林,

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

其他回答

基于其他答案,我做了一个通用的扩展函数,它识别你的父母,并相应地使用参数:

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

}

and

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

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

val params = FrameLayout.LayoutParams(
    ViewGroup.LayoutParams.MATCH_PARENT,
    ViewGroup.LayoutParams.MATCH_PARENT
)
params.setMargins(0, 0, 0, 400)
binding.container.setLayoutParams(params)

使用芬兰湾的科特林,

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

用于快速的单行设置

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

但是要小心LayoutParams的任何错误使用,因为这将没有if语句实例检查

就像今天一样,最好的办法可能是使用AirBnB提供的巴黎图书馆。

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

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

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

@Styleable and @Style