Place ImageView over Button android

The reason is actually very simple. 🙂 We are so caught up thinking in 2D that we overlook the elevation – in Z.

There is nothing wrong with your first layout. The Button simply has a higher elevation than the ImageView – exactly 1dp higher. Therefore, no matter how you arrange the two views, the Button rises above.

A bit of proof:

A Button, by default gets the Widget.Material.Button style:

<!-- Bordered ink button -->
<style name="Widget.Material.Button">
    <item name="background">@drawable/btn_default_material</item>
    <item name="textAppearance">?attr/textAppearanceButton</item>
    <item name="minHeight">48dip</item>
    <item name="minWidth">88dip</item>
    <item name="stateListAnimator">@anim/button_state_list_anim_material</item>
    <item name="focusable">true</item>
    <item name="clickable">true</item>
    <item name="gravity">center_vertical|center_horizontal</item>
</style>

The attribute that introduces this elevation is android:stateListAnimator. StateListAnimator is similar to StateListDrawable, and provides state change animations. The complete xml is here: Link. But here’s the base state of the button:

<!-- base state -->
<item android:state_enabled="true">
    <set>
        <objectAnimator android:propertyName="translationZ"
                        android:duration="@integer/button_pressed_animation_duration"
                        android:valueTo="0"
                        android:startDelay="@integer/button_pressed_animation_delay"
                        android:valueType="floatType"/>
        <objectAnimator android:propertyName="elevation"
                        android:duration="0"
                        android:valueTo="@dimen/button_elevation_material"
                        android:valueType="floatType" />
    </set>
</item>

As you can see, the elevation value for the button is set to @dimen/button_elevation_material:

<dimen name="button_elevation_material">1dp</dimen>

And that’s how the ImageView ends up being behind/below the Button.

So, what can we do?

A straight-forward solution would be to set the ImageView's elevation to the same amount – 1dp.

Another solution, which will require a bit of work, is to remove the Button's elevation rather than change ImageView's. Based on the default StateListAnimator, we can create our own – and remove the elevation. Then, in your res/values-v21/styles.xml, define a style that inherits from Widget.Material.Button:

<style name="MyDepressedButtonStyle" parent="android:Widget.Material.Button">
    <item name="android:stateListAnimator">@anim/customized_state_animator</item>
</style>

Now, set this style on your Button:

<Button
    style="@style/MyDepressedButtonStyle"
    ....
    .... />

Edit:

Actually, we can apply the customized StateListAnimator directly:

<Button
    android:stateListAnimator="@anim/customized_state_animator"
    ....
    .... />

No need to take the scenic route!

Leave a Comment