Como colocar / sobrepor (z-index) uma visão acima de outra visão no android

230

Eu tenho um layout linear que consiste em visualização de imagem e visualização de texto, um abaixo do outro em um layout linear.

<LinearLayout android:orientation="horizontal" ... >
 <ImageView 
     android:id="@+id/thumbnail"
     android:layout_weight="0.8" 
     android:layout_width="0dip"
     android:layout_height="fill_parent">
 </ImageView>
 <TextView 
    android:id="@+id/description"
    android:layout_weight="0.2"
    android:layout_width="0dip"
    android:layout_height="wrap_content">
 </TextView>

Algumas regras podem estar faltando, isso é para dar uma idéia de como o layout é exibido. Eu quero outra exibição de texto pequena, digamos 50dip de comprimento e largura, colocada sobre a visualização de imagem, por "sobre" eu quis dizer mais o índice z do que a visualização de imagem. Quero colocar isso, no centro e acima (sobreposição) da visualização de imagem.

Quero saber como podemos colocar uma visualização acima da outra, com diferentes índices z (de preferência em layout linear)?

Sentou
fonte

Respostas:

295

Você não pode usar um LinearLayout para isso, mas pode usar um FrameLayout. Em a FrameLayout, o índice z é definido pela ordem em que os itens são adicionados, por exemplo:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/my_drawable"
        android:scaleType="fitCenter"
        />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|center"
        android:padding="5dp"
        android:text="My Label"
        />
</FrameLayout>

Nesse caso, o TextView seria desenhado na parte superior do ImageView, na parte inferior central da imagem.

Kevin Coppock
fonte
Sim, eu fiz isso usando o próprio layout do quadro depois de passar pela documentação. Obrigado.
sentou
11
Existe uma vantagem em usar o FrameLayout em vez do RelativeLayout para isso?
Ixx
12
O FrameLayout não se relaciona a outras visualizações no grupo, apenas as coloca em camadas em relação ao pai. RelativeLayout é mais para posicionamento em relação a outros itens.
22412 Kevin Coppock
3
Oi kcoppock meu celular (hdpi) não respeita a ordem z no layout do quadro, mas eu tenho uma outra (xhdpi) e respeito essa ordem, você sabe por que fazer isso? Desde já, obrigado! : D
Merlí Escarpenter Pérez
1
A partir da API 21 / KitKat, agora você pode usar setZ e translationZ; o hack FrameLayout não é mais necessário (finalmente!). Esta deve ser a resposta preferida para desenvolvimento 5.0+ moderna: stackoverflow.com/a/29703860/358578
pbarranis
183

Tente .bringToFront():

http://developer.android.com/reference/android/view/View.html#bringToFront%28%29

diyism
fonte
3
também podemos usar isso em arquivos xml?
Anúncios
2
Eu estava procurando algo para trazer minha visão para alterar o itz zindex durante a animação de tradução.
DeltaCap019 25/10
Você poderia encontrar uma solução para animação de tradução?
NAkhmedov 15/09/14
9
bringChildToFront () apenas muda o índice de modo de exibição dentro do seu pai
Zar E Ahmer
4
esta parafusos toda a ordem de layout
Jemshit Iskenderov
66

RelativeLayout funciona da mesma maneira, a última imagem no layout relativo vence.

jt-gilkeson
fonte
14
A menos que você use a elevação, também precisará do maior valor.
Sami Kuhmonen
5
Esta pergunta foi feita e respondida antes da elevação existir. O uso da elevação não corrigirá o problema se o seu aplicativo tiver um minSdk menor que o Lollipop (em telefones pré-pirulito, o layout parecerá errado se você confiar apenas na elevação) - você ainda precisará prestar atenção à ordem do layout. Você está certo, porém, de que se usar elevação no componente inferior - você definitivamente precisa ter pelo menos o mesmo ou mais alto no topo.
Jt-gilkeson
27

Alterando a ordem do sorteio

Uma alternativa é alterar a ordem em que as vistas são desenhadas pelo pai. Você pode ativar esse recurso no ViewGroup chamando setChildrenDrawingOrderEnabled (true) e substituindo getChildDrawingOrder (int childCount, int i) .

Exemplo:

/**
 * Example Layout that changes draw order of a FrameLayout
 */
public class OrderLayout extends FrameLayout {

    private static final int[][] DRAW_ORDERS = new int[][]{
            {0, 1, 2},
            {2, 1, 0},
            {1, 2, 0}
    };

    private int currentOrder;

    public OrderLayout(Context context) {
        super(context);
        setChildrenDrawingOrderEnabled(true);
    }

    public void setDrawOrder(int order) {
        currentOrder = order;
        invalidate();
    }

    @Override
    protected int getChildDrawingOrder(int childCount, int i) {
        return DRAW_ORDERS[currentOrder][i];
    }
}

Resultado:

Ligar OrderLayout#setDrawOrder(int)com 0-1-2 resulta em:

insira a descrição da imagem aqui insira a descrição da imagem aqui insira a descrição da imagem aqui

Tobrun
fonte
Você chama setDrawOrder (i) no onCreate () da atividade? Se eu tiver 6 widgets no meu xml, preciso inicializar cada linha de DRAW_ORDERS com uma matriz de 6 números (0-5)?
John Ward
@JohnWard O layout mostrado acima é apenas para fins de exemplo, você pode definir seu próprio comportamento em getChildDrawingOrder ().
Tobrun 22/01/19
aqui está post relacionado com a quantidade de código claro: stackoverflow.com/questions/20524162/framelayout-in-reverse
Robert
20

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

Vadim Kotov
fonte
3
Agora, essa deve ser a resposta preferida para a API 21 / KitKat / 5.0 ou superior. Felizmente, o antigo frameLayout hack não é mais necessário. Pessoalmente, não entendo a diferença entre setZ e translationZ, mas o último é um atributo e funcionou lindamente para mim. Obrigado!
Pbarranis
Para as APIs anteriores, você também pode usar o ViewCompat # setZ ().
Ali Yucel Akgul 04/10
@AliYucelAkgul se você olhar os documentos aqui , pode ver Compatibility: API < 21: No-op . Então eu acho que não vai funcionar
Vadim Kotov
@VadimKotov, eu tentei no meu aplicativo e ele simplesmente funciona.
Ali Yucel Akgul 04/10
@AliYucelAkgul bem, isso é estranho. Talvez um erro na documentação? Você tem 100% de certeza de que está funcionando para a API <21? Eu tenho uma idéia que pode mudar a ordem de pontos de vista para as APIs anteriores, mas não coisas extravagantes como elevação, etc ..
Vadim Kotov
14

Resolvi o mesmo problema adicionando android:elevation="1dp"a qual visualização você deseja sobre outra. Mas ele não pode ser exibido abaixo de 5.0 e terá uma pequena sombra; se você puder aceitá-lo, tudo bem.

Então, disse a solução mais correta que é @kcoppock.

trinta anos
fonte
7

Tente isso em um RelativeLayout:

ImageView image = new ImageView(this);
image.SetZ(float z);

Funciona para mim.

Rizzo
fonte
2
Você deveria explicar um pouco melhor. Por exemplo, onde você colocaria esse código?
#
Bem, eu coloquei no método OnCreate (). Cada imagem adicionada possui um índice z de preferência sobre as adicionadas anteriormente. Quero dizer, através do índice z, posso mudar a posição do próximo atrás do anterior.
Rizzo
5

Existe uma maneira de usar o LinearLayout. Apenas defina o marginTop do seu elemento anterior com o valor negativo correspondente e verifique se o elemento que você deseja no topo está após o elemento que você deseja abaixo em seu XML.

<linearLayout android:orientation="horizontal" ... >
<ImageView 
 android:id="@+id/thumbnail"
 android:layout_weight="0.8" 
 android:layout_width="0dip"
 android:layout_height="fill_parent"
>
</ImageView>
<TextView 
android:id="@+id/description"
android:layout_marginTop="-20dip"
android:layout_weight="0.2"
android:layout_width="0dip"
android:layout_height="wrap_content"
>
</TextView>
Tim
fonte
4

Como você não pode fazê-lo com layouts lineares, terá que optar por um RelativeLayout .

Vincent Mimoun-Prat
fonte
RelativeLayout não estende frameLayout, você tem certeza de que funcionará?
ekatz
Será. Você pode usar qualquer um dos FrameLayout ou RelativeLayout. Cada um com maneiras diferentes de colocar vistas filho. Consulte os documentos para saber mais sobre esses layouts.
Vincent Mimoun-Prat
este é o caminho a percorrer
Albert James Teddy
0

Se você estiver adicionando o modo de exibição programaticamente, poderá usar yourLayout.addView(view, 1);

onde 1 is the index.

Alexander Maslew
fonte
0

Eu uso isso, se você deseja que apenas uma visualização seja apresentada quando necessário:

containerView.bringChildToFront(topView);

containerView é o container de visualizações a serem classificadas, topView é a view que eu quero ter como a mais alta no container.

para que várias visualizações sejam organizadas, está prestes a usar setChildrenDrawingOrderEnabled (true) e substituindo getChildDrawingOrder (int childCount, int i) conforme mencionado acima.

Milan Jurkulak
fonte