В Android, как я устанавливаю поля в dp программно?

В этом, this и this thread Я попытался найти ответ о том, как установить поля на одном представлении. Однако мне было интересно, нет ли более простого способа. Я объясню, почему я предпочитаю не использовать этот подход:

У меня есть пользовательская кнопка, которая расширяет Button. Если фон установлен на что-то еще, чем фон по умолчанию (вызывая либо setBackgroundResource(int id), либо setBackgroundDrawable(Drawable d)), я хочу, чтобы поля были равны 0. Если я вызываю это:

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

Я хочу, чтобы поля были reset до -3dp (я уже читал здесь, как конвертировать из пикселей в dp, поэтому, как только я знаю, как устанавливать поля в px, я могу управлять преобразованием самостоятельно). Но так как это вызвано в классе CustomButton, родитель может варьироваться от LinearLayout до TableLayout, и я бы предпочел не получить его родителя и проверить экземпляр этого родителя. Полагаю, это тоже будет довольно впечатляюще.

Кроме того, при вызове (используя LayoutParams) parentLayout.addView(myCustomButton, newParams), я не знаю, добавляет ли он его в правильную позицию (хотя и не пробовал), например, средняя кнопка из пяти.

Вопрос: Существует ли какой-либо более простой способ установить маржу одной кнопки программно , кроме того, используя LayoutParams?

EDIT: Я знаю способ 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).

Ответ 1

Вы можете использовать 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()
);

Ответ 3

Лучший способ:

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

Надеюсь, это поможет вам.

Ответ 4

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

Ответ 5

Вот ответ "все-в-одном" с последними обновлениями:

Шаг 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, чтобы обновить margin в dp

Все два способа обновления поля выше обновляются в пикселях. Вам нужно сделать перевод dp в пиксели.

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

Теперь поместите рассчитанное значение в указанные выше функции обновления поля, и вы должны быть настроены как

Ответ 6

layout_margin - это ограничение, которое дочерний элемент представления указывает своему родительскому элементу. Однако родительская роль заключается в том, нужно ли разрешать маржу или нет. В основном, установив android: layout_margin = "10dp", ребенок просит группу родительского представления выделить пространство 10dp больше, чем его фактический размер. (padding = "10dp", с другой стороны, означает, что дочернее представление сделает свой собственный контент 10dp меньше.)

Следовательно, не все ViewGroups относятся к маржу. Самый известный пример - listview, где поля элементов игнорируются. Прежде чем вы вызовете setMargin() в LayoutParam, вы всегда должны убедиться, что текущее представление живет в ViewGroup, поддерживающем margin (например, 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);
}

Ответ 7

Этот метод позволит вам установить Margin в 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);
}

UPDATE

Вы можете изменить параметр, который вам подходит.

Ответ 8

Когда вы находитесь в пользовательском представлении, вы можете использовать getDimensionPixelSize(R.dimen.dimen_value), в моем случае я добавил поле в LayoutParams, созданное по методу init.

В котлине

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

Ответ 9

Используйте этот метод, чтобы установить маржу в дп

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

Ответ 10

Для быстрой настройки в одну строку используйте

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

но будьте осторожны при любом неправильном использовании с LayoutParams, так как это не будет иметь место, if проверка экземпляра чека

Ответ 11

Создана функция расширения 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 }
            }
}

Ответ 12

В моем примере я добавляю 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);

Ответ 13

Вы можете использовать этот метод и поставить статический размер как 20, он преобразует в соответствии с вашим устройством

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

Ответ 14

В Котлине это будет выглядеть так:

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

Ответ 15

Как и сегодня, лучше всего использовать Paris, библиотеку, предоставленную AirBnB.

Стили могут быть применены следующим образом:

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

он также поддерживает пользовательское представление (если вы расширяете представление), используя аннотации:

@Styleable and @Style

Ответ 16

Вы должны позвонить

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

вот так: your_view.setPadding(0,16,0,0)

То, что вы пытаетесь использовать, это только получатель.

Студия Android показывает, что на самом деле означает padding...() в Java:

пример заполнения Изображение показывает, что он вызывает только 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

Ответ 17

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

Мне пришлось привести мой к 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 никогда не работал для меня - устройство зависало каждый раз. Даже если это жестко закодированные числа - это только пример кода только для демонстрации.

Ответ 18

Обновлено:

Так же, как вы использовали для установки ширины и высоты ViewGroup.LayoutParams с помощью ViewGroup.LayoutParams

Вы можете использовать ViewGroup.MarginLayoutParams чтобы установить ширину, высоту и поля, довольно 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(); принимает значения слева, сверху, справа, снизу соответственно. По часовой стрелке!, Начиная слева.