Как я могу динамически установить положение обзора в Android?

102

Как я могу изменить положение обзора с помощью кода? Как изменение его положения X, Y. Является ли это возможным?

Арун Бадоле
источник

Ответы:

117

Для всего, что ниже Honeycomb (уровень API 11), вам придется использовать setLayoutParams(...).

Если вы можете ограничить поддержку Honeycomb и выше , вы можете использовать setX(...), setY(...), setLeft(...), setTop(...)и т.д.

Скоропортящийся Дэйв
источник
41
из документации 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. Точно так же у вас есть ImageViewin LinearLayoutвашего xml файла. Таким образом, вы можете установить его положение с помощью. LayoutParamsНо убедитесь, что вы выбрали в LayoutParamsсоответствии с макетом, взятым в вашем XML-файле. Существуют разные в 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; потому что по умолчанию используется ViewGroup LayoutParams
Дэвид Т.
Похоже, это не работает на Android 8+. сталкивались ли вы с подобной проблемой?
MyFlashLab
Любая идея, почему дизайнеры Andriod идут на такие проблемы, чтобы не дать программистам использовать X, Y для позиционирования вещей. В конце концов, все должно быть так нарисовано. Это говорит о том, что Android разрабатывается людьми, которые не умеют программировать.
Пол Маккарти
34

Уже есть разные допустимые ответы, но, похоже, ни один из них не предлагает должным образом, какой метод (ы) использовать в этом случае, за исключением соответствующих ограничений уровня API:

  • Если вы можете дождаться цикла макета и родительская группа представлений поддерживает MarginLayoutParams(или подкласс), установите marginLeft/ marginTopсоответственно.

  • Если вам нужно изменить позицию немедленно и постоянно (например, для привязки PopupMenu), дополнительно вызовите layout(l, t, r, b)с теми же координатами. Это вытесняет то, что система макета подтвердит позже.

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

  • Никогда не используйте setLeft()/ setRight()/ setBottom()/ setTop(), см. Ниже.

Фон : поля mLeft/ mTop/ mBottom/ mRightзаполняются из соответствующих LayoutParams в layout (). Макет вызывается неявно и асинхронно системой макета представления Android. Таким образом, установка MarginLayoutParamsкажется самым безопасным и чистым способом установить положение навсегда. Однако задержка асинхронного макета может быть проблемой в некоторых случаях, например, при использовании View для рендеринга курсора, и он должен быть перемещен и одновременно служит якорем PopupMenu. В этом случае вызовlayout() работал нормально.

Проблемы с setLeft()и setTop():

  • Одних их вызова недостаточно - также нужно позвонить setRight()и setBottom()не растягивать или сужать вид.

  • Реализация этих методов выглядит относительно сложной (= выполняется некоторая работа для учета изменений размера представления, вызванных каждым из них)

  • Кажется, они вызывают странные проблемы с полями ввода: мягкая цифровая клавиатура EditText иногда не позволяет использовать цифры

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

Стефан Хауштайн
источник
Привет, Стефан. Не могли бы вы посоветовать несколько книг или статей, где я могу понять, как работает система макетов Android. Я понимаю эту последовательность вызовов layout () onMeasure () onDraw (), но хочу узнать о ней более подробно. Заранее спасибо
Сергей Бражник
К сожалению, я не могу - лучшей и наиболее точной ссылкой, кажется, является реальный исходный код Android O :)
Stefan Haustein
Я использую setY для изменения вида, он изменится в следующем цикле макета, а не сразу?
сигнал
Как вы это определили?
Stefan Haustein
Стоит отметить, что это marginLeftможно установить с помощью setLayoutParamsa, new FrameLayout.LayoutParams(width, height)на котором вы установилиmarginLeft
lucidbrot
18

Существует библиотека под названием NineOldAndroids , которая позволяет использовать библиотеку анимации Honeycomb вплоть до первой версии.

Это означает, что вы можете определить left, right, translationX / Y с немного другим интерфейсом.

Вот как это работает:

ViewHelper.setTranslationX(view, 50f);

Вы просто используете статические методы из класса ViewHelper, передаете представление и любое значение, которое вы хотите установить.

Бен
источник
16

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

Brianmearns
источник
13

Вы можете попробовать использовать следующие методы, если используете HoneyComb Sdk (уровень API 11).

view.setX(float x);

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

view.setY(float y);

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

Надеюсь, это будет вам полезно. :)

Курица с рисом
источник
4
Я работаю над 2.2 Froyo, и эти методы в нем недоступны.
Арун Бадоле 01
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);

Вышеупомянутые методы используются для установки позиции представления относительно его родителя.

Balaji.K
источник
Извините, эти методы недоступны. Вы можете прислать мне код?
Арун Бадоле
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);

NB: обратите внимание, что вы также можете использовать imageView.setLeft (int dim), НО ЭТО НЕ УСТАНАВЛИВАЕТ положение компонента, он установит только положение левой границы компонента, остальные останутся в том же положении .

Алессандро Муцци
источник
Итак, как мы можем переместить представление в определенное положение, не влияя на исходное представление?
Джеймс
Я не уверен, что понял вашу проблему, потому что, если вы хотите переместить представление, вы измените его тем фактом, что вы его перемещаете. В любом случае, если вы хотите переместить представление поверх другого независимо от него, вам может потребоваться представление FrameLayout для вашего основного макета, тогда внутри него вы можете разместить свои независимые представления (очевидно, если вы хотите, чтобы он перемещался под вашим основным представлением, вы необходимо разместить FrameLayout перед основным)
Алессандро Муцци
3

Используйте RelativeLayout, поместите в него свой вид, получите RelativeLayout.LayoutParamsобъект из своего вида и установите поля по мере необходимости. Тогда обращайтесь requestLayout()к вашему мнению. Это единственный способ, который я знаю.

Glodos
источник
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);
Брейден Холт
источник