Програмно змінити правий край перегляду?


172

Чи може цей атрибут динамічно змінюватися в коді Java?

android:layout_marginRight

У мене є TextView, що має динамічно змінювати своє положення деяких пікселів наліво.

Як це зробити програмно?

Відповіді:


462

EDIT: Більш загальний спосіб зробити це, який не покладається на тип макета (крім того, що це тип макета, який підтримує поля):

public static void setMargins (View v, int l, int t, int r, int b) {
    if (v.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
        ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
        p.setMargins(l, t, r, b);
        v.requestLayout();
    }
}

Ви повинні перевірити документи на TextView . В основному, ви хочете отримати об'єкт LayoutParams TextView та змінити поля, а потім встановити його назад у TextView. Якщо припустити, що це в LinearLayout, спробуйте щось подібне:

TextView tv = (TextView)findViewById(R.id.my_text_view);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)tv.getLayoutParams();
params.setMargins(0, 0, 10, 0); //substitute parameters for left, top, right, bottom
tv.setLayoutParams(params);

Я не можу перевірити його зараз, тому моє кастинг може бути трохи відключений, але LayoutParams - це те, що потрібно змінити, щоб змінити поле.

ПРИМІТКА

Не забувайте, що якщо ваш TextView знаходиться всередині, наприклад, RelativeLayout , слід використовувати RelativeLayout.LayoutParams замість LinearLayout.LayoutParams


39
Просто уточнити свою відповідь на випадок, якщо інші люди цього шукають. Якщо ви створюєте TextView програмно, вам також потрібно створити новий об’єкт LinearLayout.LayoutParams, а не намагатися вийти з нього через .getLayoutParams ();
Арес

Це працює приголомшливо, і, здається, він встановлює поля в пікселях. Чи можна встановити його в dp?
SirRupertIII


Відповідно до вашої ПРИМІТКИ: я маю сумніви. Якщо перегляд тексту або кнопка знаходяться всередині рядка таблиці? Тоді що я повинен використовувати замість відносного макета, макета таблиці?
tejas

1
Пов’язана з приміткою, ви можете просто передати tv.getLayoutParams () на ViewGroup.MarginLayoutParams. Таким чином, не має значення, який макет є родичем, якщо він реалізує поля
Раду Сіміонеску

17

Використовуйте LayoutParams (як уже пояснено). Однак будьте уважні, який LayoutParams вибрати. Відповідно до https://stackoverflow.com/a/11971553/3184778, "вам потрібно використовувати той, який стосується РОБОТИ подання, над яким ви працюєте, а не власне"

Якщо, наприклад, TextView знаходиться в TableRow, тоді вам потрібно використовувати TableRow.LayoutParams замість RelativeLayout або LinearLayout


Дякуємо за уточнення!
Скотт Біггс

1
це дійсно гарно, що вам потрібно знати місце призначення текстового поля, щоб встановити поля ... ви б могли подумати, що знайдеться рішення, незалежне від призначення.
TatiOverflow

10

Використовуйте цю функцію для встановлення всіх типів поля

      public void setViewMargins(Context con, ViewGroup.LayoutParams params,      
       int left, int top , int right, int bottom, View view) {

    final float scale = con.getResources().getDisplayMetrics().density;
    // convert the DP into pixel
    int pixel_left = (int) (left * scale + 0.5f);
    int pixel_top = (int) (top * scale + 0.5f);
    int pixel_right = (int) (right * scale + 0.5f);
    int pixel_bottom = (int) (bottom * scale + 0.5f);

    ViewGroup.MarginLayoutParams s = (ViewGroup.MarginLayoutParams) params;
    s.setMargins(pixel_left, pixel_top, pixel_right, pixel_bottom);

    view.setLayoutParams(params);
}

2
Чому додаткові 0,5f?
бехеліт

2
@behelit Я знаю, що це пізно, але для тих, хто шукає ... коли ти кидаєш поплавок на int, поплавок обводиться. 0,0 -> 0,4 ​​раунди до 0, тоді як 0,5 -> 0,9 раунди до 1. Це може створити невідповідності у фінальних вставках Щоб запобігти цьому, додавання 0,5 забезпечує все округлення до 1. Чому? скажімо, що ваш поплавок становить 0,3: 0,3 + 0,5 = 0,8, що кругляє вгору до 1. Скажіть, що ваш поплавок дорівнює 0,8: 0,8 + 0,5 = 1,3, який округлюється вниз до 1. Тепер ви можете бути в безпеці в своїх знаннях про остаточне округлення (ПОВІДОМЛЕННЯ: ми додаємо 0,5, а не віднімаємо, щоб не отримати негативний int)
Psest328

7

Оновлення: Android KTX

Модуль Core KTX пропонує розширення для загальних бібліотек, що входять до складу Android-системи, androidx.core.viewсеред них.

dependencies {
    implementation "androidx.core:core-ktx:{latest-version}"
}

Наступні функції розширення зручні для вирішення поля:

Встановлює поля всіх осей у ViewGroupвікнах MarginLayoutParams. (Розмір повинен бути наданий у пікселях; див. Останній розділ, якщо ви хочете працювати з dp)

inline fun MarginLayoutParams.setMargins(@Px size: Int): Unit
// E.g. 16px margins
val params = (myView.layoutParams as ViewGroup.MarginLayoutParams)
params.setMargins(16)

Оновлення поля в ViewGroup's ViewGroup.MarginLayoutParams.

inline fun MarginLayoutParams.updateMargins(
    @Px left: Int = leftMargin, 
    @Px top: Int = topMargin, 
    @Px right: Int = rightMargin, 
    @Px bottom: Int = bottomMargin
): Unit
// Example: 8px left margin 
params.updateMargins(left = 8)

Оновлення відносних полів у ViewGroups MarginLayoutParams(початок / кінець замість ліво / праворуч).

inline fun MarginLayoutParams.updateMarginsRelative(
    @Px start: Int = marginStart, 
    @Px top: Int = topMargin, 
    @Px end: Int = marginEnd, 
    @Px bottom: Int = bottomMargin
): Unit
// E.g: 8px start margin 
params.updateMargins(start = 8)

Наступні властивості розширення зручні для отримання поточних запасів:

inline val View.marginBottom: Int
inline val View.marginEnd: Int
inline val View.marginLeft: Int
inline val View.marginRight: Int
inline val View.marginStart: Int
inline val View.marginTop: Int
// E.g: get margin bottom
val bottomPx = myView1.marginBottom
  • Використання dpзамість px:

Якщо ви хочете працювати з dp(незалежними від щільності пікселями) замість них px, вам потрібно спочатку їх перетворити. Ви можете легко зробити це за допомогою наступного властивості розширення:

val Int.px: Int
    get() = (this * Resources.getSystem().displayMetrics.density).toInt()

Тоді ви можете викликати попередні функції розширення, такі як:

params.updateMargins(start = 16.px, end = 16.px, top = 8.px, bottom = 8.px)
val bottomDp = myView1.marginBottom.dp

Стара відповідь:

У Kotlin ви можете оголосити функцію розширення на зразок:

fun View.setMargins(
    leftMarginDp: Int? = null,
    topMarginDp: Int? = null,
    rightMarginDp: Int? = null,
    bottomMarginDp: Int? = null
) {
    if (layoutParams is ViewGroup.MarginLayoutParams) {
        val params = layoutParams as ViewGroup.MarginLayoutParams
        leftMarginDp?.run { params.leftMargin = this.dpToPx(context) }
        topMarginDp?.run { params.topMargin = this.dpToPx(context) }
        rightMarginDp?.run { params.rightMargin = this.dpToPx(context) }
        bottomMarginDp?.run { params.bottomMargin = this.dpToPx(context) }
        requestLayout()
    }
}

fun Int.dpToPx(context: Context): Int {
    val metrics = context.resources.displayMetrics
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), metrics).toInt()
}

Тоді ви можете назвати це так:

myView1.setMargins(8, 16, 34, 42)

Або:

myView2.setMargins(topMarginDp = 8) 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.