239

I would like to define the z order of the views of a RelativeLayout in Android.

I know one way of doing this is calling bringToFront.

Is there are better way of doing this? It would be great if I could define the z order in the layout xml.

Onik
  • 19,396
  • 14
  • 68
  • 91
hpique
  • 119,096
  • 131
  • 338
  • 476

13 Answers13

326

The easiest way is simply to pay attention to the order in which the Views are added to your XML file. Lower down in the file means higher up in the Z-axis.

Edit: This is documented here and here on the Android developer site. (Thanks @flightplanner)

Steve Haley
  • 55,374
  • 17
  • 77
  • 85
  • Hmm, I'm not sure. I'll dig around later to see what I can find. However the same principle is used elsewhere; canvases (used for 2d graphics) work the same way. So I suspect this won't change. Still, it's a good thing to check. – Steve Haley Apr 10 '10 at 23:25
  • 16
    This is unfortunately not always possible to change. For example, in a relative layout, each elements can only be layed out with respect to those previously defined in the file – Casebash May 20 '10 at 02:20
  • 69
    Casebash, I don't think thats neccessarily the case you just have to use the "@+id/your_element_before_its_defined" and then use the same id in the element you define later. I might be wrong about this, these layouts are very tricky for me, but I definitely get the impression that it works. – tjb May 02 '11 at 15:14
  • 7
    tjb is right (and I'm glad he is). Use @+id with the very first mention of the id e.g. layout_above="@+id/some_id" – Michiel Jun 07 '11 at 11:58
  • 3
    You can also put into a values xml file, and then you can reference it anywhere. – karl Mar 21 '13 at 17:58
  • 8
    I know I'm about 3 years late to the party, but in answer to @hpique, this is documented [here](http://developer.android.com/reference/android/view/View.html#Drawing) – HexAndBugs Mar 31 '13 at 17:44
  • Almost 4 years late to the party, but what happens when Relative view is used. If you say view A at the top, View B below A and then View C below A. then which one is at the front (B or C)? – Snake Nov 25 '13 at 16:53
  • 2
    @Snake C will be in front/on top, assuming in the actual file you define the views in order A, B, C. Remember, lower down in the file means higher up the Z axis as it is added afterwards. – Steve Haley Nov 25 '13 at 17:48
  • 1
    Please note that you can use view.setZ(float) starting from API level 21 – Vadim Kotov Apr 17 '15 at 16:00
  • 1
    From my experience, this works only if the lower view is not a button, otherwise the button is still picking up the click event. – yongsunCN Oct 10 '16 at 14:39
  • @yongsunCN The click events still propagate down the view hierarchy if the upper views don't define click listeners. However, _visually_ the further-down-the-file view is shown on top. – Steve Haley Oct 10 '16 at 15:08
91

If you want to do this in code you can do

View.bringToFront();

see docs

QAMAR
  • 2,684
  • 22
  • 28
79

Please note, buttons and other elements in API 21 and greater have a high elevation, and therefore ignore the xml order of elements regardless of parent layout. Took me a while to figure that one out.

Daniel Wilson
  • 18,838
  • 12
  • 85
  • 135
  • 19
    the solution to this bug for me was to call setElevation(1000) on the view which I want to be rendered over the button. – fire in the hole May 22 '17 at 16:23
  • 1
    setElevation() requires API level 21 – dp2050 Mar 11 '20 at 02:17
  • Had TextView defined after in a Button and they were below it in the preview render. Fixed it by adding `tools:elevation="10dp"`. Note the use of the Tools namespace as this was not an issue on device apparently. Could just switch to the Android namespace if ever needed. – Slion Feb 05 '23 at 09:19
26

In Android starting from API level 21, items in the layout file get their Z order both from how they are ordered within the file, as described in correct answer, and from their elevation, a higher elevation value means the item gets a higher Z order.

This can sometimes cause problems, especially with buttons that often appear on top of items that according to the order of the XML should be below them in Z order. To fix this just set the android:elevation of the the items in your layout XML to match the Z order you want to achieve.

I you set an elevation of an element in the layout it will start to cast a shadow. If you don't want this effect you can remove the shadow with code like so:

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

I haven't found any way to remove the shadow of a elevated view through the layout xml.

lejonl
  • 1,453
  • 15
  • 20
16

I encountered the same issues: In a relative layout parentView, I have 2 children childView1 and childView2. At first, I put childView1 above childView2 and I want childView1 to be on top of childView2. Changing the order of children views did not solve the problem for me. What worked for me is to set android:clipChildren="false" on parentView and in the code I set:

childView1.bringToFront();

parentView.invalidate();
Tony Vu
  • 4,251
  • 3
  • 31
  • 38
  • 3
    This is working, and Android makes me so sad. `child.bringToFront()` with `parent.invalidate()` works, but `parent.bringChildToFront(child)` does not. Where is the logic that we all expect from an OS? – Oliver Hausler May 06 '15 at 15:21
  • In order to animate some views (translations in X and Y), I tried several combinations for LinearLayout, FrameLayout and RelativeLayout but there were always issues (related to overlaps or not proportional sizes). Finally `android:clipChildren="false"` did the trick. Thank you! – JCarlosR Jun 21 '19 at 00:54
16

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

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
16

Thought I'd add an answer since the introduction of the

android:translationZ

XML field changed things a tad. The other answers that suggest running

childView1.bringToFront();

parentView.invalidate();

are totally spot on EXCEPT for that this code will NOT bring childView1 in front of any view with a hardcoded android:translationZ in the XML file. I was having problems with this, and once I removed this field from the other views, bringToFront() worked just fine.

ThePartyTurtle
  • 2,276
  • 2
  • 18
  • 32
7

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

Use ViewCompat.setElevation(view, float); for backward compatibility

More methods ViewCompat.setZ(v, pixels) and ViewCompat.setTranslationZ(v, pixels)

Another way collect buttons or view array and use addView to add to RelativeLayout

Qamar
  • 4,959
  • 1
  • 30
  • 49
5

childView.bringToFront() didn't work for me, so I set the Z translation of the least recently added item (the one that was overlaying all other children) to a negative value like so:

lastView.setTranslationZ(-10);

see https://developer.android.com/reference/android/view/View.html#setTranslationZ(float) for more

kip2
  • 6,473
  • 4
  • 55
  • 72
1

You can use custom RelativeLayout with redefined

protected int getChildDrawingOrder (int childCount, int i)

Be aware - this method takes param i as "which view should I draw i'th". This is how ViewPager works. It sets custom drawing order in conjuction with PageTransformer.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Petrov Dmitrii
  • 228
  • 1
  • 10
1

Or put the overlapping button or views inside a FrameLayout. Then, the RelativeLayout in the xml file will respect the order of child layouts as they added.

fullmoon
  • 8,030
  • 5
  • 43
  • 58
0

Check if you have any elevation on one of the Views in XML. If so, add elevation to the other item or remove the elevation to solve the issue. From there, it's the order of the views that dictates what comes above the other.

The Fluffy T Rex
  • 430
  • 7
  • 22
0

You can use below code sample also for achieving the same

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

This is backward compatible. Here mCardView is a view which should be below sourceView.

Ankit
  • 1,916
  • 2
  • 20
  • 33