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

402

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

У меня есть пользовательская кнопка, которая расширяет кнопку. Если задан фон, отличный от фона по умолчанию (вызывая либо 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).

stealthjong
источник

Ответы:

798

Вы должны использовать, 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()
);
throrin19
источник
152
Из какого пакета я должен импортировать этот конкретный LayoutParams?
stealthjong
7
setMargins использовал px, и вы будете использовать dp, мое преобразование верно: dp -> px, чтобы установить правильное значение поля.
throrin19
6
@ChristiaandeJong RelativeLayout.LayoutParams
2013 г.
16
это зависит от вашего текущего макета. Если вы находитесь в LinearLayout, используйте LinearLayout.LayoutParams. RelativeLayout.LayoutParams в противном случае
throrin19
5
Вы должны импортировать layoutParams, который является вашим родительским макетом ex. <linearlayout> <lativelayout> <gridlayout> и вы работаете с макетом сетки. тогда вам нужно использовать относительныеlayout.layoutparams
Sruit A.Suk
228

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

Люстен Элдер
источник
19
Правильно, но нет необходимости устанавливать его обратно, измененные параметры автоматически отражаются. Таким образом, вы можете удалить строку: vector8.setLayoutParams (params);
Wirsing
LayaoutParams обычно создают путаницу при настройке поля ... Так что этот MarginLayoutParams очень полезен. Спасибо
Атул Бхардвадж
4
вам НЕОБХОДИМО установить setLayoutParams (params) после пометки изменений
Leo Droidcoder
я нашел MarginLayoutParams как новый класс сегодня # Спасибо.
Тушар Пандей
Не работает для Buttonпросмотра: ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) button.getLayoutParams()возвращаетсяnull
Константин Конопко
119

Лучший способ когда-либо:

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

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

Хирен Патель
источник
1
я сталкиваюсь с проблемой, когда я устанавливаю setMargins (holder.vCenter, 0, 20, 0,0); как это его оставить поле с обеих сторон (сверху и снизу), что не так с вышеуказанными параметрами?
Arbaz.in
1
Потрясающий идеальный ответ !! Спасибо!!
SJD
33
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);
sagits
источник
15

Вот ответ «все в одном» с последними обновлениями:

Шаг 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 в пиксели.

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

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

Fangming
источник
9

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

Следовательно, не все ViewGroups уважают маржу . Самый печально известный пример - просмотр списка, где поля элементов игнорируются. Прежде чем вызывать 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);
}
Ян Вонг
источник
9

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

ОБНОВИТЬ

Вы можете изменить параметр, который соответствует вашим потребностям.

neferpitou
источник
8

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

val layoutParams = (yourView?.layoutParams as? MarginLayoutParams)
layoutParams?.setMargins(40, 40, 40, 40)
yourView?.layoutParams = layoutParams
Морозов
источник
3

Когда вы находитесь в пользовательском представлении, вы можете использовать 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);
    }
}
aldajo92
источник
2

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

 public static int dpToPx(int dp) 
      {
          float scale = context.getResources().getDisplayMetrics().density;
       return (int) (dp * scale + 0.5f);
  }
Дишант Каватра
источник
1

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

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);
Ридван Бин Сарвар
источник
1

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

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

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

Дасер Басьюни
источник
1

Создана функция расширения 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 }
            }
}
Дэвид Ким
источник
1

В моем примере я добавляю 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);
Раджив Шетти
источник
0

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

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

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

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

@Styleable and @Style
Sonique
источник
0

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

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

Али Макнамара
источник
-1

Вы можете использовать, 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 соответственно. По часовой стрелке!, Начиная слева.

mmmcho
источник