Ziad Akiki
Ziad Akiki

Reputation: 2680

Android - Shadow size not affected when changing elevation

I'm developing an Android application targeting android Lollipop and above and I looked into the elevation property to achieve a shadow under the elements (namely buttons, cards and bottom navigation view).

The issue I'm facing is that when changing the android:elevation value within the XML, the shadow size is not affected. What I've tried and read:

Concerning the code, you can find below my button style and the fragment's layout.

Button Style

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:app="http://schemas.android.com/apk/res-auto">
    <style name="Search" parent="@android:style/Widget.Button">
        <item name="android:gravity">center_vertical|start</item>
        <item name="android:textColor">@color/lightText</item>
        <item name="android:textSize">@dimen/main_search_textSize</item>
        <item name="android:background">@drawable/main_search</item>
        <item name="android:focusable">true</item>
        <item name="android:clickable">true</item>
        <item name="android:text">@string/search</item>
        <item name="android:elevation">@dimen/main_search_elevation</item>
        <item name="android:drawableStart">@drawable/ic_main_search</item>
        <item name="android:paddingLeft">@dimen/main_search_padding</item>
        <item name="android:paddingRight">@dimen/main_search_padding</item>
        <item name="android:drawablePadding">@dimen/main_search_padding</item>
    </style>
</resources>

Fragment Layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingStart="@dimen/activity_horizontal_margin"
    android:paddingEnd="@dimen/activity_horizontal_margin"
    android:background="@color/lightBackground"
    android:clipToPadding="false">

    <androidx.appcompat.widget.AppCompatButton
        style="@style/Search"
        android:layout_width="match_parent"
        android:layout_height="@dimen/main_search_height"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

dimens.xml

<resources>
    <dimen name="activity_horizontal_margin">24dp</dimen>
    <dimen name="activity_vertical_margin">24dp</dimen>

    <dimen name="main_nav_icon_padding">6dp</dimen>

    <dimen name="main_search_height">54dp</dimen>
    <dimen name="main_search_marginTop">72dp</dimen>
    <dimen name="main_search_elevation">24dp</dimen>
    <dimen name="main_search_padding">16dp</dimen>
    <dimen name="main_search_textSize">20sp</dimen>
</resources>

And here's what I'm getting (no matter what the elevation property is):

Search button screenshot

Note that the shadow does change when long pressing the button, and it is not being clipped in any way.

Therefore, any idea what seems to be the issue?

Upvotes: 3

Views: 1291

Answers (1)

ljk
ljk

Reputation: 1616

Hey your question seemed really useful so I decided to have a go at it. I hope this helps you, if someone has a better way do post it.

Firstly I think the main issue is that the Button Style you are using has some StateListAnimator that is controlling the elevation for your button, so no matter what value you set as elevation it gets overridden. The easiest solution is to simply add

<item name="android:stateListAnimator">@null</item>

to your custom "Search" style and now the button will show the elevation you are setting using <item name="android:elevation">@dimen/main_search_elevation</item> in the same style.

But this will be like a static view which will give you an elevated look but no cool animated changes when you click or long press etc.

In order to have those animations you will need to create your custom StateListAnimator using ObjectAnimator. I created one as an example. Create android resource directory animator and add an xml file where you will write the custom animation required.

Here's the custom_animator.xml i created

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!--For when your button is pressed-->
    <item
        android:state_enabled="true"
        android:state_pressed="true">
        <set>
            <objectAnimator
                android:duration="300"
                android:propertyName="translationZ"
                android:valueTo="12dp"
                android:valueType="floatType" />
            <objectAnimator
                android:duration="300"
                android:propertyName="elevation"
                android:valueTo="12dp"
                android:valueType="floatType" />
        </set>
    </item>

    <!--For when your button is in its normal state-->
    <item android:state_enabled="true">
        <set>
            <objectAnimator
                android:duration="300"
                android:propertyName="translationZ"
                android:valueTo="4dp"
                android:valueType="floatType" />
            <objectAnimator
                android:duration="300"
                android:propertyName="elevation"
                android:valueTo="4dp"
                android:valueType="floatType" />
        </set>
    </item>

</selector>

You will need to set custom dimensions as per your requirement for when the button is in its base state and when it is pressed. I made use of 4dp and 12dp respectively as it seemed more than enough

That's it, now you simply need to add this as a stateListAnimator to your style

    <item name="android:stateListAnimator">@animator/custom_animator</item>

and it should be working. Note that in this case again android:elevation won't work only the values defined in your animator will reflect. So you may remove <item name="android:elevation">@dimen/main_search_elevation</item> as its isn't needed.

Referenced a few blogs on medium and other posts on SO, to know how all this worked. Try this and let us know if it worked for you.

Upvotes: 2

Related Questions