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

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

我有一个自定义按钮扩展按钮。如果背景被设置为默认背景以外的其他内容(通过调用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)时,我不知道这是否会将它添加到正确的位置(但是还没有尝试过),比如5个按钮的中间。

问:有没有更简单的方法以编程方式设置单个Button 除了使用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);
}
}

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

575719 次浏览

你应该使用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 - NOT WORKING !! !

需要使用类型: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

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

因此,不是所有的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);
}

此方法将允许您在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);
}

更新

您可以根据需要更改参数。

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

最好的方式:

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

希望这对你有所帮助。

以下是最新更新的综合答案:

第一步,更新页边距

基本思想是获取边缘,然后更新它。更新将自动应用,您不需要设置它。要获得布局参数,只需调用这个方法:

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设置margin,你需要以这种方式更新margin

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

步骤2,在dp中更新边缘

上面两种更新边缘的方法都是以像素为单位更新的。你需要把dp转换成像素。

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

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

就像今天一样,最好的方法可能是使用巴黎,一个由AirBnB提供的库。

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

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

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

@Styleable and @Style

使用此方法设置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);

用于快速的单行设置

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

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

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

在芬兰湾的科特林

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);
}
}
((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从来不为我工作-设备每次都会崩溃。尽管这些都是硬编码的数字,但这只是用于演示目的的代码示例。

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

在我的例子中,我通过编程的方式添加了一个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);


你可以使用这种方法,并把静态迪曼像20它转换根据您的设备

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

你可以使用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();分别接收左、上、右、下的值。顺时针方向!,从左边开始。

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

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

如果你想添加一个边缘到你的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。谢谢

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

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

这就是我在kotlin中所做的

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

感兴趣的人可以使用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();
}
}

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

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

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

使用Android KTX,你可以这样做:

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

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

使用芬兰湾的科特林,

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

对我来说,我使用的是ViewGroup。themedbutton组件中的LayoutParams。使用ViewGroup。LayoutParams不能使用setMargin。

相反,使用MarginLayoutParams如下,它为我工作。

ViewGroup.MarginLayoutParams params =new ViewGroup.MarginLayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.MATCH_PARENT
);
params.setMargins(0,8,0,0);

对我来说,下面的代码是有效的

buttonLinearLayout.layoutParams as MarginLayoutParams).apply
{
top.run {
topMargin = resources.getDimension(R.dimen.spacing).toInt()
}
}
val params = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
params.setMargins(0, 0, 0, 400)
binding.container.setLayoutParams(params)