36

I think the title is pretty explicit about my problem... So here is my layout :

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">

                <Button
                    android:id="@+id/button_action"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="Login" />

                <ProgressBar
                    android:id="@+id/progress_bar"
                    android:layout_width="50dp"
                    android:layout_height="50dp"
                    android:layout_centerInParent="true"/>

            </RelativeLayout>

On android SDKs < 21, no problem, the ProgressBar is correctly displayed over the Button and centered in the Button. But on Android 5.0, the ProgressBar is displayed behind the Button.

So you can see it's correctly positionned it when you activate the option "Show layout bounds" in Developer Options settings, but you can't see anything on the screen without that option.

Would anybody know how to fix this? I guess it's a matter of elevation recently introduced, but I really don't know how to take care of it. For the record, I'm using the recently released Theme.AppCompat style from the support.v7.

EDIT:

I also tried to apply setElevation(0) and setTranslationY(0) to the Button programmatically but it didn't change anything. So I wonder if it has to deal with the elevation.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
MathieuMaree
  • 7,453
  • 6
  • 26
  • 31

6 Answers6

92

You can add the android:translationZ attribute to the ProgressBar:

<ProgressBar
    android:id="@+id/progress_bar"
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:translationZ="2dp"
    android:layout_centerInParent="true"/>
Adil Hussain
  • 30,049
  • 21
  • 112
  • 147
wpiwonski
  • 1,284
  • 12
  • 6
13

Same issue here, my simple "hack" was too wrap the Button into another FrameLayout. This way I don't care about the api version and other elevation issue ;)

<FrameLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center" >

        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
                <Button
                    android:id="@+id/button_action"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="Login" />
        </FrameLayout>

        <ProgressBar
            android:id="@+id/progress_bar"
            android:layout_width="50dp"
            android:layout_height="50dp" />
</FrameLayout>
Tobliug
  • 2,992
  • 30
  • 28
7

Same question being asked here, with a better explanation of the issue:

https://stackoverflow.com/a/27216368/235910

To quote @CommonsWare:

The problem appears Android 5.0's elevation property. Apparently, the RelativeLayout Z-axis ordering is tied into elevation. If both widgets have the same elevation, the RelativeLayout will determine the Z-axis order -- you can see that if you were to switch your layout to be both Button widgets, for example. However, if one widget (Button) has an elevation, and another widget (ImageView) does not, the elevation will take precedence.

You can remove the Button elevation via android:stateListAnimator="@null" or by defining your own custom animator. Or, you can add some elevation to your ImageView to get it to be higher on the Z axis than is the Button.

Community
  • 1
  • 1
LambergaR
  • 2,433
  • 4
  • 24
  • 34
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – Alex K Dec 18 '14 at 21:03
1

It is better to set android:translationZ more than 2dp. Your view/widget will disappear when you press the button. I explained the reason here.

<!-- Elevation when button is pressed -->
<dimen name="button_elevation_material">1dp</dimen>
<!-- Z translation to apply when button is pressed -->
<dimen name="button_pressed_z_material">2dp</dimen>

Button have these two values and defined in the framework.

Community
  • 1
  • 1
zzas11
  • 1,115
  • 9
  • 16
0

If you add 'androidx.core:core' to your build.gradle, you can use this code for API < 21:

ViewCompat.setTranslationZ(viewToElevate, 5);
sp00ky
  • 151
  • 9
0

By default, if you want to show a view on top of a Button, it should have an elevation of at least 2dp.

This is caused by the fact that the elevation of a button is governed by their stateListAnimator. So long as it has one, setting the elevation to the button itself doesn't do anything. The stateListAnimator of Widget.MaterialComponents.Button has a default elevation of @dimen/mtrl_btn_elevation (2dp), so that's the elevation you have to take into account.

Doing android:stateListAnimator="@null" will also work, but that will get rid of any shadow effects at the button.

Cristan
  • 12,083
  • 7
  • 65
  • 69