在 this、this 和 this 线程中,我试图找到有关如何在单个视图上设置边距的答案。但是,我想知道是否没有更简单的方法。我将解释为什么我不想使用这种方法:
我有一个扩展按钮的自定义按钮。如果背景设置为默认背景以外的其他内容(通过调用 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 之外,还有什么更简单的方法可以以编程方式设置单个 Button 的边距?
编辑:我知道 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)。
您应该使用 LayoutParams
设置按钮边距:
LayoutParams params = new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
params.setMargins(left, top, right, bottom);
yourbutton.setLayoutParams(params);
根据您使用的布局,您应该使用 RelativeLayout.LayoutParams
或 LinearLayout.LayoutParams
。
并将您的 dp 度量转换为像素,请尝试以下操作:
Resources r = mContext.getResources();
int px = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
yourdpmeasure,
r.getDisplayMetrics()
);
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
Button
视图:ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) button.getLayoutParams()
返回 null
有史以来最好的方式:
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);
希望这会帮助你。
requestLayout()
?
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);
这是最近更新的多合一答案:
第 1 步,更新保证金
基本思想是获取利润然后更新它。更新将自动应用,您无需重新设置。要获取布局参数,只需调用此方法:
LayoutParams layoutParams = (LayoutParams) yourView.findViewById(R.id.THE_ID).getLayoutParams();
LayoutParams
来自您的视图布局。如果视图来自线性布局,则需要导入 LinearLayout.LayoutParams
。如果您使用相对布局,请导入 LinearLayout.LayoutParams
等。
现在,如果您使用 Layout_marginLeft
、Right
等设置边距,则需要以这种方式更新边距
layoutParams.setMargins(left, top, right, bottom);
如果您使用新的 layout_marginStart
设置边距,则需要以这种方式更新边距
layoutParams.setMarginStart(start);
layoutParams.setMarginEnd(end);
第 2 步,更新 dp 中的边距
以上两种更新边距的方法都是以像素为单位更新的。您需要将 dp 转换为像素。
float dpRatio = context.getResources().getDisplayMetrics().density;
int pixelForDp = (int)dpValue * dpRatio;
现在将计算值放入上述保证金更新函数中,您应该已经设置好了
使用 Android KTX,您可以执行以下操作:
yourView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
setMargins(0, 0, 0, 0)
}
在 Kotlin 中,它看起来像这样:
val layoutParams = (yourView?.layoutParams as? MarginLayoutParams)
layoutParams?.setMargins(40, 40, 40, 40)
yourView?.layoutParams = layoutParams
此方法可让您在 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);
}
更新
您可以更改适合您需要的参数。
layout_margin 是视图子告诉其父视图的约束。然而,选择是否允许保证金是父母的角色。基本上通过设置 android:layout_margin="10dp",孩子请求父视图组分配比其实际大小大 10dp 的空间。 (另一方面,padding="10dp" 表示子视图会将自己的内容缩小 10dp。)
因此,并非所有 ViewGroup 都尊重边距。最臭名昭著的例子是列表视图,其中项目的边距被忽略。在将 setMargin()
调用到 LayoutParam 之前,您应该始终确保当前视图位于支持边距(例如 LinearLayouot 或 RelativeLayout)的 ViewGroup 中,并将 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);
}
您可以使用此方法并放置像 20 这样的静态维度,它会根据您的设备进行转换
public static int dpToPx(int dp)
{
float scale = context.getResources().getDisplayMetrics().density;
return (int) (dp * scale + 0.5f);
}
简单的 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)
}
这也允许您制作 horizontal
或 vertical
变体:
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 } 包装修改
这就是我在 kotlin
中所做的
fun View.setTopMargin(@DimenRes dimensionResId: Int) {
(layoutParams as ViewGroup.MarginLayoutParams).topMargin = resources.getDimension(dimensionResId).toInt()
}
如果你想为 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。谢谢
使用此方法在 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);
当您在自定义视图中时,您可以使用 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);
}
}
使用 Kotlin,
yourLayoutId.updateLayoutParams<ViewGroup.MarginLayoutParams> {
setMargins(15,15,15,15)
}
对于快速的单线设置使用
((LayoutParams) cvHolder.getLayoutParams()).setMargins(0, 0, 0, 0);
但请注意对 LayoutParams 的任何错误使用,因为这将没有 if
语句实例 chech
为那些可能觉得很方便的人创建了一个 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);
对于那些感兴趣的人,使用 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()
您也可以添加对其他父视图组的支持
使用此方法可以正确设置 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));
与今天一样,最好的可能是使用 AirBnB 提供的库 Paris。
然后可以像这样应用样式:
Paris.style(myView).apply(R.style.MyStyle);
它还支持使用注释的自定义视图(如果您扩展视图):
@Styleable and @Style
对我来说,我在主题按钮组件中使用 ViewGroup.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)
((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 从来没有为我工作过——设备每次都会崩溃。尽管这些是硬编码的数字 - 这只是用于演示目的的代码示例。
您可以使用 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 的值。顺时针!,从左边开始。