Як я можу динамічно встановити положення перегляду в Android?


102

Як я можу змінити положення зору за допомогою коду? Як і зміна свого X, Y положення. Це можливо?

Відповіді:


117

Що-небудь нижче сотового (API рівня 11) вам доведеться використовувати setLayoutParams(...).

Якщо ви можете обмежити підтримку Honeycomb і вище , ви можете використовувати setX(...), setY(...), setLeft(...), setTop(...)і т.д.


40
з документів setTop () developer.android.com/reference/android/view/… : sets the top position of this view relative to its parent. This method is meant to be called by the layout system and should not generally be called otherwise, because the property may be changed at any time by the layout.- то, може, це не така гарна ідея;)
katzenhut

47

Так, ви можете динамічно встановлювати положення перегляду в Android. Точно так же у вас є ImageViewв LinearLayoutвашій XML file.So ви можете встановити свою позицію через LayoutParams.Але не забудьте взяти в LayoutParamsвідповідно до розташування , прийнятим у вашій XML file.There різні в LayoutParamsзалежності від компоновки взятої.

Ось код, який потрібно встановити:

    LayoutParams layoutParams=new LayoutParams(int width, int height);
    layoutParams.setMargins(int left, int top, int right, int bottom);
    imageView.setLayoutParams(layoutParams);

Сподіваюся, вам буде корисно встановити позицію.


15
також зауважте, що ви повинні імпортувати android.widget.LinearLayout.LayoutParams; тому що за замовчуванням - LayoutParams ViewGroup
David T.

Схоже, це не працює на Android 8+. ви стикалися з подібною проблемою?
MyFlashLab

Будь-яка ідея, чому дизайнери Andriod ідуть на такі проблеми, щоб утримати прогмерів від використання X, Y для позиціонування речей. Зрештою все має бути намальовано таким чином. Це говорить про те, що Android розробляють люди, які не можуть кодувати.
Пол Маккарті

33

Вже є різні дійсні відповіді, але жоден, здається, не дозволяє правильно запропонувати, який метод (и) використовувати в тому випадку, за винятком відповідних обмежень рівня API:

  • Якщо ви можете дочекатися циклу компонування і підтримує батьківську групу перегляду MarginLayoutParams(або підклас), встановіть marginLeft/ marginTopвідповідно.

  • Якщо вам потрібно змінити позицію негайно та наполегливо (наприклад, для якоря PopupMenu), додатково зателефонуйте layout(l, t, r, b)з тими ж координатами. Це передбачає, що система компонування буде підтверджена пізніше.

  • Для негайних (тимчасових) змін (наприклад, анімації) використовуйте setX()/ setY()замість цього. У випадках, коли розмір батьків не залежить від WRAP_CHILDREN, може бути непогано використовувати setX()/ setY()виключно.

  • Ніколи не використовуйте setLeft()/ setRight()/ setBottom()/ setTop(), див. Нижче.

Фон : mLeft/ mTop/ mBottom/ mRightполя заповнюються з відповідних макетпарм у макеті (). Система макета перегляду Android виразно та асинхронно називає макет. Таким чином, встановлення, MarginLayoutParamsздається, є найбезпечнішим і найчистішим способом постійного встановлення положення. Однак затримка асинхронного макета може бути проблемою в деяких випадках, наприклад, при використанні View для візуалізації курсору, і він повинен бути перестановлений і одночасно служити якорем PopupMenu. У цьому випадку дзвінки layout()спрацювали мені добре.

Проблеми з setLeft()та setTop()є:

  • Викликати їх самотужки недостатньо - вам також потрібно зателефонувати setRight()та setBottom()уникати розтягування чи зменшення виду.

  • Реалізація цих методів виглядає відносно складною (= виконання певної роботи для врахування змін розміру перегляду, викликаних кожним із них)

  • Здається, вони викликають дивні проблеми з полями введення: м'яка цифрова клавіатура EditText іноді не дає цифр

setX()і setY()працювати поза системою компонування, і відповідні значення розглядаються як додаткове зміщення до значень ліво / верх / низ / право, визначене системою компонування, зміщуючи подання відповідно. Вони, здається, додані для анімації (де потрібен негайний ефект без проходження циклу компонування).


Привіт Стефане. Не могли б ви порадити кілька книг чи статей, де я можу зрозуміти, як працює система верстки Android. Я розумію, що послідовність компонування () onMeasure () onDraw () викликає, але хочу дізнатися про неї детальніше. Заздалегідь дякую
Сергій Бражник

На жаль, я не можу - найкращим та найвиразнішим посиланням здається фактичний вихідний код Android O :)
Stefan Haustein

Я використовую setY для зміни подання, він змінюється в наступному циклі компонування, а не відразу?
сигнал

Як ти це визначив?
Стефан Хауштейн

Варто зазначити, що marginLeftможна встановити, використовуючи за допомогою setLayoutParamsтого, new FrameLayout.LayoutParams(width, height)на якому ви встановилиmarginLeft
lucidbrot

18

Існує бібліотека під назвою NineOldAndroids , яка дозволяє використовувати бібліотеку анімації стільникових мереж аж до першої версії.

Це означає, що ви можете визначити лівий, правий, translationX / Y з дещо іншим інтерфейсом.

Ось як це працює:

ViewHelper.setTranslationX(view, 50f);

Ви просто використовуєте статичні методи з класу ViewHelper, передаєте подання та яке значення, яке ви хочете встановити.


16

Я б рекомендував використовувати setTranslationXі setTranslationY. Я лише зараз починаю це робити, але це, мабуть, є найбезпечнішим і бажаним способом перегляду огляду. Я думаю, це дуже залежить від того, що саме ти намагаєшся зробити, але це для мене добре працює для 2D-анімації.


13

Якщо ви використовуєте HoneyComb Sdk (API рівня 11), ви можете спробувати скористатися такими методами.

view.setX(float x);

Параметр x - візуальна х позиція цього виду.

view.setY(float y);

Параметр y - візуальне y положення цього виду.

Я сподіваюся, що вам це буде корисно. :)


4
Я працюю над 2.2 Froyo, і ці методи в ньому відсутні.
Arun Badole

7

Для підтримки всіх рівнів API ви можете використовувати його так:

ViewPropertyAnimator.animate(view).translationYBy(-yourY).translationXBy(-yourX).setDuration(0);

Тому що він хоче змінити позицію і вище рішення краще і не потребує анімації
FireZenk

Також переклад може спричинити (частково) перегляд екрана
mewa

4

Встановіть ліве положення цього виду відносно його батьківського:

view.setLeft(int leftPosition);

Встановіть правильну позицію цього виду щодо його батьків:

view.setRight(int rightPosition);

Встановіть верхнє положення цього виду відносно його батьківського:

view.setTop(int topPosition);

Встановіть нижнє положення цього виду відносно його батьківського:

view.setBottom(int bottomPositon);

Вищеописані способи використовуються для встановлення позиції подання, пов'язаного з його батьківським.


Вибачте, ці методи недоступні. Чи можете ви надіслати мені який-небудь код?
Арун Бадоле

4
"Цей метод призначений називатися системою компонування, і його взагалі не слід називати інакше, тому що властивість може бути змінена в будь-який момент макетом."
GDanger

4

Використовуйте LayoutParams. Якщо ви використовуєте LinearLayout, вам потрібно імпортувати android.widget.LinearLayout.LayoutParams, інакше імпортуйте належну версію LayoutParams для використовуваного макета, або це спричинить ClassCastException , тоді:

LayoutParams layoutParams = new LayoutParams(int width, int height);
layoutParams.setMargins(int left, int top, int right, int bottom);
imageView.setLayoutParams(layoutParams);

Примітка. Зауважте, що ви можете також використовувати imageView.setLeft (int dim), АЛЕ ЦЕ НЕ БУДЕ встановити позицію компонента, він встановить лише положення лівої межі компонента, решта залишиться на тому самому положенні .


тож як ми можемо перенести погляд у певну позицію, не впливаючи на початковий вигляд?
Джеймс

Я не впевнений, що я зрозумів вашу проблему, тому що якщо ви хочете перенести вигляд, ви зміните її через те, що ви пересуваєтесь. У будь-якому випадку, якщо ви хочете перемістити погляд на інший незалежно від нього, вам може знадобитися перегляд FrameLayout, який виб'є ваш основний макет, тоді всередині нього ви можете розмістити свої незалежні погляди (очевидно, якщо ви хочете, щоб він переміщувався під основним видом ви повинні розмістити рамку FrameLay перед вашою основною)
Алессандро Муцці

3

Використовуйте RelativeLayout, розміщуйте його в ньому, отримуйте RelativeLayout.LayoutParamsоб'єкт від вашого виду і встановлюйте поля, як вам потрібно. Потім зателефонуйте requestLayout()на свій погляд. Це єдиний спосіб, який я знаю.


1

Я виявив, що @Stefan Haustein дуже близький до мого досвіду, але не впевнений на 100%. Моя пропозиція:

  • setLeft()/ setRight()/ setBottom()/ setTop()Чи не буде працювати іноді.
  • Якщо ви хочете тимчасово встановити позицію (наприклад, для анімації, на яку не впливає ієрахія), коли подання додано та показано , просто використовуйте setX()/setY() замість цього. (Можливо, ви хочете шукати більше в різниці setLeft()іsetX() )
  • І зауважте, що X, Y здаються абсолютними, і це було підтримано AbsoluteLayout, який зараз застарілий. Таким чином, ви відчуваєте, що X, Y, ймовірно, більше не підтримується. І так, є, але лише частково. Це означає, що якщо ваш погляд додано, setX (), setY () буде працювати ідеально ; в іншому випадку, коли ви намагаєтеся додати вигляд у макет групи перегляду (наприклад, FrameLayout, LinearLayout, RelativeLayout), ви повинні встановити його LayoutParams з marginLeft, marginTop замість ( setX (), setY () у цьому випадку іноді не працюватиме).
  • Встановити положення подання marginLeft та marginTop - це несинхронізований процес. Тому для оновлення ієрархії потрібно трохи часу . Якщо ви будете використовувати перегляд відразу після встановлення для нього поля , ви можете отримати неправильне значення .

0

Одне, що слід пам’ятати при позиціонуванні, - це те, що кожен вид має індекс відносно його батьківського подання. Отже, якщо у вас лінійний макет із трьома підпереглядами, у кожного підвідстеження буде індекс: 0, 1, 2 у вищезазначеному випадку.

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

int childCount = parent.getChildCount();
parentView.addView(newView, childCount);

Крім того, ви можете замінити представлення даних, використовуючи щось таке:

int childIndex = parentView.indexOfChild(childView);
childView.setVisibility(View.GONE);

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