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

我有一个自定义按钮扩展按钮。如果背景被设置为默认背景以外的东西(通过调用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)。


当前回答

创建了一个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 }
            }
}

其他回答

使用此方法可以正确地设置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));

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

这也允许你做出水平或垂直的变化:

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

注意:如果margin设置失败,你可能在渲染之前太早了,这意味着params == null。尝试用myView包装修改。Post {margin = 10}

((FrameLayout.LayoutParams) linearLayout.getLayoutParams()).setMargins(450, 20, 0, 250);
        linearLayout.setBackgroundResource(R.drawable.smartlight_background);

我不得不将我的linearLayout转换为FrameLayout,因为它继承了linearLayout,并在那里设置了边缘,这样活动就只出现在屏幕的一部分,与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从来不为我工作-设备每次都会崩溃。尽管这些都是硬编码的数字,但这只是用于演示目的的代码示例。

Layout_margin是子视图告诉父视图的约束。然而,是否允许保证金是由母公司决定的。基本上通过设置android:layout_margin="10dp",子视图请求父视图组分配比其实际大小大10dp的空间。(另一方面,padding="10dp"意味着子视图将自己的内容缩小10dp。)

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

下面的函数应该可以做到这一点。但是,请确保将RelativeLayout替换为父视图的类型。

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

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

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

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