Como posso definir dinamicamente a posição de visualização no Android?

102

Como posso alterar a posição de visualização por meio do código? Como mudar sua posição X, Y. É possível?

Arun Badole
fonte

Respostas:

117

Para qualquer coisa abaixo do Honeycomb (API de nível 11), você terá que usar setLayoutParams(...).

Se você pode limitar seu apoio para Honeycomb e se você pode usar o setX(...), setY(...), setLeft(...), setTop(...), etc.

Perecíveis Dave
fonte
40
dos documentos de 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.- então talvez não seja uma ideia tão boa;)
katzenhut
47

Sim, você pode definir dinamicamente a posição de visualização no Android. Da mesma forma você tem um ImageViewno LinearLayoutdo seu xml file.So você pode definir a sua posição através LayoutParams.Mas não deixe de fazer LayoutParamsde acordo com o layout tomado em seu xml file.There são diferentes LayoutParamsde acordo com o layout tomadas.

Aqui está o código a ser definido:

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

Espero que seja útil para você definir a posição.

AkashG
fonte
15
observe também que você deve importar android.widget.LinearLayout.LayoutParams; porque o padrão é LayoutParams do ViewGroup
David T.
Isso não parece estar funcionando no Android 8+. você enfrentou um problema semelhante?
MyFlashLab
Qualquer ideia de por que os designers do Andriod se deram ao trabalho de impedir os programadores de usar X, Y para posicionar as coisas. Eventualmente, tudo tem que ser desenhado dessa forma. Isso sugere que o Android está sendo projetado por pessoas que não sabem programar.
Paul McCarthy
33

Já existem diferentes respostas válidas, mas nenhuma parece sugerir adequadamente quais métodos usar nesse caso, exceto para as restrições de nível de API correspondentes:

  • Se você pode esperar por um ciclo de layout e o grupo de visão pai suporta MarginLayoutParams(ou uma subclasse), defina marginLeft/ de marginTopacordo.

  • Se você precisar mudar a posição imediatamente e persistentemente (por exemplo, para uma âncora PopupMenu), adicionalmente chame layout(l, t, r, b)com as mesmas coordenadas. Isso antecipa o que o sistema de layout confirmará mais tarde.

  • Para mudanças imediatas (temporárias) (como animações), use setX()/ no setY()lugar. Nos casos em que o tamanho do pai não depende de WRAP_CHILDREN, pode ser adequado usar setX()/ setY()exclusivamente.

  • Nunca use setLeft()/ setRight()/ setBottom()/ setTop(), veja abaixo.

Antecedentes : Os mLeft/ mTop/ mBottom/ mRightcampos ficar cheia dos LayoutParams correspondentes no layout (). O layout é chamado de forma implícita e assíncrona pelo sistema de layout de visualização do Android. Portanto, definir o MarginLayoutParamsparece ser a maneira mais segura e limpa de definir a posição permanentemente. No entanto, o atraso de layout assíncrono pode ser um problema em alguns casos, por exemplo, ao usar uma visualização para renderizar um cursor, e deve ser reposicionado e servir como uma âncora do PopupMenu ao mesmo tempo. Nesse caso, ligar layout()funcionou bem para mim.

Os problemas com setLeft()e setTop()são:

  • Ligar sozinho não é suficiente - você também precisa ligar setRight()e setBottom()evitar esticar ou diminuir a visualização.

  • A implementação desses métodos parece relativamente complexa (= fazer algum trabalho para contabilizar as mudanças no tamanho da visualização causadas por cada um deles)

  • Eles parecem causar problemas estranhos com os campos de entrada: o teclado numérico virtual EditText às vezes não permite dígitos

setX()e setY()trabalhar fora do sistema de layout, e os valores correspondentes são tratados como um deslocamento adicional para os valores esquerdo / superior / inferior / direito determinados pelo sistema de layout, mudando a visualização de acordo. Eles parecem ter sido adicionados para animações (onde um efeito imediato sem passar por um ciclo de layout é necessário).

Stefan Haustein
fonte
Olá Stefan. Você poderia aconselhar alguns livros ou artigos onde eu possa entender como funciona o sistema de layout do Android. Eu entendo essa sequência de chamadas de layout () onMeasure () onDraw (), mas quero saber mais detalhes. Agradecemos antecipadamente
Sergey Brazhnik
Infelizmente não posso - a melhor e mais definitiva referência parece ser o código-fonte real do Android O :)
Stefan Haustein
Eu uso setY para alterar a visualização, ele muda no próximo ciclo de layout, não é imediato?
sinal
Como você determinou isto?
Stefan Haustein
É importante ressaltar que o marginLeftpode ser definido usando setLayoutParamscom um new FrameLayout.LayoutParams(width, height)no qual você definiu omarginLeft
lucidbrot
18

Existe uma biblioteca chamada NineOldAndroids , que permite que você use a biblioteca de animação Honeycomb até a versão um.

Isso significa que você pode definir a esquerda, a direita, translationX / Y com uma interface ligeiramente diferente.

É assim que funciona:

ViewHelper.setTranslationX(view, 50f);

Você apenas usa os métodos estáticos da classe ViewHelper, passa a visão e o valor que você deseja definir.

Ben
fonte
16

Eu recomendaria usar setTranslationXe setTranslationY. Estou apenas começando a fazer isso, mas parece ser a maneira mais segura e preferida de mover uma vista. Acho que depende muito do que exatamente você está tentando fazer, mas está funcionando bem para mim para animação 2D.

brianmearns
fonte
13

Você pode tentar usar os métodos a seguir, se estiver usando HoneyComb Sdk (API de nível 11).

view.setX(float x);

O parâmetro x é a posição visual x desta vista.

view.setY(float y);

O parâmetro y é a posição visual desta visualização.

Espero que seja útil para você. :)

Arroz de frango
fonte
4
Estou trabalhando no 2.2 Froyo e esses métodos não estão disponíveis nele.
Arun Badole
7

Para suporte a todos os níveis de API, você pode usá- lo assim:

ViewPropertyAnimator.animate(view).translationYBy(-yourY).translationXBy(-yourX).setDuration(0);
Orr
fonte
Porque ele quer mudar a posição e a solução acima é melhor e não precisa de animação
FireZenk
Além disso, a tradução pode fazer com que a visualização fique (parcialmente) fora da tela
mewa
4

Defina a posição esquerda desta visualização em relação ao pai:

view.setLeft(int leftPosition);

Defina a posição correta desta visualização em relação ao seu pai:

view.setRight(int rightPosition);

Defina a posição superior desta visualização em relação à sua principal:

view.setTop(int topPosition);

Defina a posição inferior desta visualização em relação ao seu pai:

view.setBottom(int bottomPositon);

Os métodos acima são usados ​​para definir a posição da visualização em relação ao seu pai.

Balaji.K
fonte
Desculpe, esses métodos não estão disponíveis. Você pode me enviar qualquer código?
Arun Badole
4
"Este método deve ser chamado pelo sistema de layout e geralmente não deve ser chamado de outra forma, porque a propriedade pode ser alterada a qualquer momento pelo layout."
GDanger de
4

Use LayoutParams. Se você estiver usando um LinearLayout, terá que importar android.widget.LinearLayout.LayoutParams, caso contrário, importe a versão adequada de LayoutParams para o layout que você está usando, ou isso causará uma ClassCastException , então:

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

NB: Observe que você também pode usar imageView.setLeft (int dim), MAS ISTO NÃO definirá a posição do componente, ele definirá apenas a posição da borda esquerda do componente, o resto permanecerá na mesma posição .

Alessandro Muzzi
fonte
então, como podemos mover a visualização para uma posição específica sem afetar a visualização original?
James
Não tenho certeza se entendi seu problema porque se você quiser mover uma visualização, você a mudará pelo fato de estar movendo-a. De qualquer forma, se você quiser mover uma visão sobre outra independentemente dela, você pode precisar de uma visão FrameLayout para expandir seu layout principal, então, dentro dela, você pode colocar suas visões independentes (obviamente, se você quiser mover sob sua visão principal, tem que colocar o FrameLayout antes do principal)
Alessandro Muzzi
3

Use RelativeLayout, coloque sua visão nele, pegue o RelativeLayout.LayoutParamsobjeto de sua visão e defina as margens conforme necessário. Então invoque requestLayout()sua opinião. Esta é a única maneira que conheço.

glodos
fonte
1

Descobri que @Stefan Haustein chega muito perto da minha experiência, mas não tenho certeza 100%. Minha sugestão é:

  • setLeft()/ setRight()/ setBottom()/ setTop()às vezes não funciona.
  • Se você quiser definir uma posição temporariamente (por exemplo, para fazer animação, não afetou uma hierarquia) quando a visualização foi adicionada e exibida , basta usar setX()/ emsetY() vez disso. (Você pode querer pesquisar mais diferenças setLeft()esetX() )
  • E observe que X, Y parecem ser absolutos e era compatível com AbsoluteLayout, que agora está obsoleto. Assim, você sente que X, Y provavelmente não é mais compatível. E sim, é, mas apenas parcialmente. Isso significa que se sua visualização for adicionada, setX (), setY () funcionarão perfeitamente ; caso contrário, ao tentar adicionar uma visualização ao layout do grupo de visualização (por exemplo, FrameLayout, LinearLayout, RelativeLayout), você deve definir seu LayoutParams com marginLeft, marginTop (setX (), setY () neste caso não funcionarão às vezes).
  • Definir a posição da visualização por marginLeft e marginTop é um processo não sincronizado . Portanto, é necessário um pouco de tempo para atualizar a hierarquia . Se você usar a visualização imediatamente após definir a margem para ela, poderá obter um valor errado .
Nguyen Tan Dat
fonte
0

Uma coisa a ter em mente com o posicionamento é que cada visualização possui um índice relativo à visualização pai. Portanto, se você tiver um layout linear com três subvisualizações, cada uma das subvisualizações terá um índice: 0, 1, 2 no caso acima.

Isso permite que você adicione uma visualização à última posição (ou final) em uma visualização pai fazendo algo assim:

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

Como alternativa, você pode substituir uma visualização usando algo como o seguinte:

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

parentView.addView(newView, childIndex);
Braden Holt
fonte