Definindo a ordem Z de visualizações do RelativeLayout no Android

226

Gostaria de definir a ordem z das visualizações de um RelativeLayout no Android.

Eu sei que uma maneira de fazer isso é chamar bringToFront.

Existe melhor maneira de fazer isso? Seria ótimo se eu pudesse definir a ordem z no xml do layout.

hpique
fonte
4
View.bringToFront (); é o anser
Shirish Herwade

Respostas:

314

A maneira mais fácil é simplesmente prestar atenção à ordem em que as Views são adicionadas ao seu arquivo XML. Mais abaixo no arquivo significa mais alto no eixo Z.

Editar: está documentado aqui e aqui no site do desenvolvedor do Android. (Obrigado @flightplanner)

Steve Haley
fonte
16
Infelizmente, isso nem sempre é possível mudar. Por exemplo, em um layout relativo, cada elemento só pode ser disposto com relação aos definidos anteriormente no arquivo
Casebash
67
Casebash, não acho que seja o caso necessário, basta usar o "@ + id / your_element_before_its_defined" e depois usar o mesmo ID no elemento que você definir mais tarde. Posso estar errado sobre isso, esses layouts são muito complicados para mim, mas definitivamente tenho a impressão de que funciona.
tjb
7
tjb está certo (e estou feliz que ele esteja). Use @ + id com a primeira menção da id por exemplo layout_above = "@ + id / some_id"
Michiel
3
Você também pode colocar <item type = "id" name = "<your_id>" /> em um arquivo xml de valores e, em seguida, pode referenciá-lo em qualquer lugar.
karl
8
Eu sei que estou prestes 3 anos atrasado para a festa, mas em resposta a @hpique, isso está documentado aqui
HexAndBugs
88

Se você quiser fazer isso no código, poderá fazer

View.bringToFront();

ver documentos

QAMAR
fonte
68

Observe que os botões e outros elementos na API 21 ou superior têm uma elevação alta e, portanto, ignoram a ordem xml dos elementos, independentemente do layout pai. Levei um tempo para descobrir isso.

Daniel Wilson
fonte
16
a solução para esse bug para mim foi chamar setElevation (1000) na exibição que eu quero que seja renderizada sobre o botão.
fogo no buraco
setElevation () requer API nível 21
dp2050 11/03
21

No Android, a partir do nível 21 da API, os itens no arquivo de layout obtêm sua ordem Z, tanto na forma como são ordenados no arquivo, conforme descrito na resposta correta, quanto na elevação, um valor de elevação mais alto significa que o item recebe uma ordem Z mais alta .

Às vezes, isso pode causar problemas, especialmente com botões que geralmente aparecem em cima de itens que, de acordo com a ordem do XML, devem estar abaixo deles na ordem Z. Para corrigir isso, defina os android:elevationitens no XML do layout para corresponder à ordem Z que você deseja atingir.

Se você definir uma elevação de um elemento no layout, ele começará a projetar uma sombra. Se você não deseja esse efeito, pode remover a sombra com o código da seguinte forma:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
   myView.setOutlineProvider(null);
}

Não encontrei nenhuma maneira de remover a sombra de uma visualização elevada através do xml de layout.

lejonl
fonte
1
Como mencionado nos comentários, você pode usar android:elevation="1000dp". Nenhuma sombra é renderizada dessa maneira.
Vadim Kotov
15

Encontrei os mesmos problemas: Em um layout relativo parentView, tenho 2 filhos childView1 e childView2. Inicialmente, coloquei childView1 acima de childView2 e quero que childView1 esteja no topo de childView2. Alterar a ordem dos pontos de vista das crianças não resolveu o problema para mim. O que funcionou para mim é definir android: clipChildren = "false" no parentView e no código que defini:

childView1.bringToFront();

parentView.invalidate();
Tony Vu
fonte
2
Isso está funcionando, e o Android me deixa tão triste. child.bringToFront()com parent.invalidate()obras, mas parent.bringChildToFront(child)não. Onde está a lógica que todos esperamos de um sistema operacional?
Oliver Hausler
Para animar algumas visualizações (traduções em X e Y), tentei várias combinações para LinearLayout, FrameLayout e RelativeLayout, mas sempre havia problemas (relacionados a sobreposições ou tamanhos não proporcionais). Finalmente android:clipChildren="false"fiz o truque. Obrigado!
JCarlosR
15

Observe que você pode usar a view.setZ(float)partir do nível 21. da API. Aqui você pode encontrar mais informações.

Vadim Kotov
fonte
13

Pensei em acrescentar uma resposta desde a introdução do

android: translationZ

O campo XML mudou um pouco as coisas. As outras respostas que sugerem execução

childView1.bringToFront();

parentView.invalidate();

estão totalmente no EXCEPT, pois esse código NÃO colocará childView1 na frente de qualquer visualização com um android: translationZ codificado no arquivo XML. Eu estava tendo problemas com isso e, depois que removi esse campo dos outros modos de exibição, bringToFront () funcionou bem.

ThePartyTurtle
fonte
Isto também é verdade para os android 5 deelevation
shelll
5

API 21 tem view.setElevation(float)build-in

Use ViewCompat.setElevation(view, float);para compatibilidade com versões anteriores

Mais métodos ViewCompat.setZ(v, pixels)eViewCompat.setTranslationZ(v, pixels)

Outra maneira de coletar botões ou exibir a matriz e usar addViewpara adicionar ao RelativeLayout

Qamar
fonte
1

Você pode usar personalizado RelativeLayoutcom redefinido

protected int getChildDrawingOrder (int childCount, int i)

Esteja ciente - este método usa param icomo "qual visualização devo desenhar i'th". É assim que ViewPagerfunciona. Ele define a ordem de desenho personalizada em conjunto com PageTransformer.

Petrov Dmitrii
fonte
0

Verifique se você tem alguma elevação em uma das vistas em XML. Nesse caso, adicione elevação ao outro item ou remova a elevação para resolver o problema. A partir daí, é a ordem dos pontos de vista que determina o que vem acima do outro.

O fofo T Rex
fonte
0

Ou coloque o botão ou as vistas sobrepostas dentro de um FrameLayout. Em seguida, o RelativeLayout no arquivo xml respeitará a ordem dos layouts filhos à medida que forem adicionados.

Badr
fonte
0

Você pode usar o exemplo de código abaixo também para obter o mesmo

ViewCompat.setElevation(sourceView, ViewCompat.getElevation(mCardView)+1);

Isso é compatível com versões anteriores. Aqui mCardViewestá uma visão que deve estar abaixo sourceView.

Ankit
fonte