Placing/Overlapping(z-index) a view above another view in android
Asked Answered
C

13

266

I have a linear layout which consists of imageview and textview , one below another in a linear layout.

<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>

Some rules might be missing , this is to give an idea , how layout looks. I want another small text view of say 50dip in length and width , placed over the imageview, by "over" I meant z-index more than imageview , I want to place this , in the center and above(overlapping) the imageview.

I want to know how can we place one view above the other, with varying z-index (preferably in linear layout) ?

Convolute answered 15/11, 2010 at 8:3 Comment(0)
U
320

You can't use a LinearLayout for this, but you can use a FrameLayout. In a FrameLayout, the z-index is defined by the order in which the items are added, for example:

<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>

In this instance, the TextView would be drawn on top of the ImageView, along the bottom center of the image.

Undershirt answered 13/1, 2011 at 20:41 Comment(10)
Yeah I did it using frame layout itself after going through documentation. Thank you.Convolute
Is there an advantage of using FrameLayout instead RelativeLayout for this?Shimberg
FrameLayout doesn't relate to other views in the group, it just layers them in regard to the parent. RelativeLayout is more for positioning relative to other items.Undershirt
by using #13915109 am able to show part of previous and next page as shown in image above,but now I don't want to show sharp edges on images.I want them to blur towards edges..please guide me on how can i use z-index for achieving the sameDeterrent
use match_parent, not fill_parentDenisdenise
FrameLayout is the key. I've even used this to draw things over map views and in some situations, though I have no idea why, it works where a relative layout does not.Depart
Hi kcoppock my mobile (hdpi) doesn't respect z-order in frame layout, but i have an other (xhdpi) and respect this order, do you know why do this? Thanks in advance! :DManometer
And it is applicable for the elements in the DrawerLayout also. This will be helpful while using the two list views in the Navigation Drawer.Ezmeralda
As of API 21 / KitKat you can now use setZ and translationZ; the FrameLayout hack is no longer needed (finally!). This should be the preferred answer for modern 5.0+ development: https://mcmap.net/q/108784/-placing-overlapping-z-index-a-view-above-another-view-in-androidSumbawa
Not the actual solution for me, but with a little modification it solved my problem. Thanks!Aisha
A
202

Give a try to .bringToFront():

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

Amphiaster answered 7/9, 2011 at 10:23 Comment(9)
can we use this in xml files too?Comines
I was looking for something such to bring my view to change itz zindex during translation animation.Dirge
Could u find a solution for translation animation?Isatin
bringChildToFront() just changes the index of the View inside its parentDareen
Take care about Nepster's comment. Because bringChildToFront() changes the index, the items' layout order is changed (changing x and y coordinates). It does not only change the z order, as one might think.Colophon
Saved my day. Thanks. This is especially required if we are toggling the views on and off programtically in betweenOxfordshire
killer answer, your unorthodox-ed and not like other fools out here, who gave the same conventional(copy cats) answers... your true legendProfusion
this screws the whole layout orderBronco
bringToFront or make sure that the layer/frame you want to be drawn is added first at framelayout index: rootLayout.addView(shadow); rootLayout.addView(viewPager,0);//to make dropshadow effect visible , draw viewpager at least layerPoor
F
72

RelativeLayout works the same way, the last image in the relative layout wins.

Foreign answered 24/2, 2012 at 0:3 Comment(2)
Unless you use elevation, then you also need the largest value in that.Pereira
This question was asked and answered before elevation existed. Using elevation won't fix the issue if your app has a minSdk less than Lollipop (on pre-lollipop phones the layout will look wrong if you rely on just elevation) - you still have to pay attention to the order of the layout. You are right though, that if you use elevation on the bottom component - you definitely need to have at least the same or higher on the top.Foreign
S
31

Changing the draw order

An alternative is to change the order in which the views are drawn by the parent. You can enable this feature from ViewGroup by calling setChildrenDrawingOrderEnabled(true) and overriding getChildDrawingOrder(int childCount, int i).

Example:

/**
 * 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];
    }
}

Output:

Calling OrderLayout#setDrawOrder(int) with 0-1-2 results in:

enter image description here enter image description here enter image description here

Schifra answered 26/8, 2016 at 8:36 Comment(3)
Do you call setDrawOrder(i) in the activity's onCreate()? If I have 6 widgets in my xml, do I need to initialize each row of DRAW_ORDERS with an array of 6 numbers (0-5)?Nihility
@JohnWard the layout shown above is solely for example purposes, you can define your own behaviour in getChildDrawingOrder().Schifra
here's related post with much clear code: https://mcmap.net/q/110874/-framelayout-in-reverseBluegill
T
28

I solved the same problem by add android:elevation="1dp" to which view you want it over another. But it can't display below 5.0, and it will have a little shadow, if you can accept it, it's OK.

So, the most correct solution which is @kcoppock said.

Twobit answered 11/6, 2018 at 3:13 Comment(1)
Don't know why this is so underrated answer.Protective
G
27

You can use view.setZ(float) starting from API level 21. Here you can find more info.

Guesswarp answered 17/4, 2015 at 15:47 Comment(8)
This should now be the preferred answer for API 21 / KitKat / 5.0 or higher. The old frameLayout hack is thankfully no longer required. Personally I don't understand the difference between setZ and translationZ, but the latter is an attribute and worked beautifully for me. Thanks!Sumbawa
For the previous apis you can use ViewCompat#setZ() too.Scholasticism
@AliYucelAkgul if you look at the docs here, you can see Compatibility: API < 21: No-op . So I think it will not workGuesswarp
@VadimKotov, I have tried in my app and it just works.Scholasticism
@AliYucelAkgul well, that is strange. Maybe a mistake in the docs? Are you 100% sure it is working for API < 21? I have an idea that it can change order of views for the previous APIs, but no fancy stuff like elevation, etc..Guesswarp
@VadimKotov, I just pushed my code but let me check it again.Scholasticism
I would assume translationZ would translate from the current z index, ie: z index = 3, so translationZ = 4 makes z = 7, whereas setZ just sets the z index.Suspensoid
since setTranslationZ() and setZ() were added in API 21, I'm gonna have to wait on using them for a few years because the current min API level is 17 for the app (and I suspect for most apps) I'm working on.Carmellacarmelle
S
8

Try this in a RelativeLayout:

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

It works for me.

Skywriting answered 9/11, 2017 at 22:56 Comment(2)
You should explain a bit better. For instance where would you put this code?Beals
Well, I put it in OnCreate() method. Each image added has an z index of preference over the ones added before. I mean, through the z index I can change the position of the next behind the previous.Skywriting
Y
6

There is a way to use LinearLayout. Just set the marginTop of your previous element to the corresponding negative value, and make sure the element you want on top is after the element you want below in your 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>
Ysabel answered 10/3, 2014 at 16:36 Comment(0)
O
4

AFAIK you cannot do it with linear layouts, you'll have to go for a RelativeLayout.

Obscure answered 15/11, 2010 at 9:41 Comment(3)
RelativeLayout does not extend frameLayout, are you sure that it will work?Metchnikoff
It will. You can use any of FrameLayout or RelativeLayout. Each having different ways of placing child views. Refer to the docs to know more about those layouts.Obscure
this is the way to goAntonina
C
2

I use this, if you want only one view to be bring to front when needed:

containerView.bringChildToFront(topView);

containerView is container of views to be sorted, topView is view which i want to have as top most in container.

for multiple views to arrange is about to use setChildrenDrawingOrderEnabled(true) and overriding getChildDrawingOrder(int childCount, int i) as mentioned above.

Charkha answered 23/11, 2019 at 21:10 Comment(0)
U
1

If you are adding the View programmatically, you can use yourLayout.addView(view, 1);

where 1 is the index.

Unconditioned answered 21/11, 2019 at 22:46 Comment(0)
E
1

Try this in a RelativeLayout:

example XML:

<ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:contentDescription="@string/todo"
        app:srcCompat="@drawable/ic_offer_close_outline"
        app:tint="@color/colorWhite"
        android:translationZ="999dp" />

example java:

ImageView image = new ImageView(this);
image.SetZ(float z);
Eclogite answered 17/2, 2023 at 21:12 Comment(0)
F
0

Use android:transformZ. It works also with LinearLayout.

Francyne answered 17/8, 2022 at 22:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.