Reputation: 2680
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):
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
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