How to get Darker shadows on Android
Tags: android, programming, mobile, design
Published: 2022-01-20 17:15:31

A blog post about shadows might be an old topic but it never hurts to revisit it and put it out there, especially for newcomers to Android development.

I am sure you know you can get Android components to have a shadow by using the `elevation` property, this one works on components that have backgrounds such as buttons (if the component doesn't have background there will be no shadow), this shadow is provided to components by the system, that is why there are things that you can't modify from it but others can be changed such as the transparency of the shadow, you can achieve this with the theme attributes called `ambientShadowAlpha` and `spotShadowAlpha` these ones are float numbers that are normally below 0.25, which makes the shadow a bit hard to see on light backgrounds. These are theme attributes so you can set them in your theme like this:

```
<style name="Theme.Shadows" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
    ....
    <!-- Customize your theme here. -->
    <item name="android:ambientShadowAlpha">1</item>
    <item name="android:spotShadowAlpha">1</item>
</style>
```

This is an example of how it looks when modifying theses attributes:

![Both attributes to 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qsht9z0xvutmdjqpnmi0.png)
![Only ambientShadowAlpha](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5dsy9u8ebbd36yg45yfv.png)
![Only spotShadowAlpha](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/95xmronp52h4xim9zx7l.png)

> First image: Both attributes to 1, Second image: only `ambientShadowAlpha` to 1, Third image: only `spotShadowAlpha` to 1

You can play around with these two attributes and use them as best suits your case, keep in mind that if you apply this to the app theme, it will affect all shadows that are set through `elevation` in your app/activity, depending on how you are using your themes, and **you can't apply this through widgets styles** such as `buttonStyles` or `materialButtonStyles` in the theme or directly through the style attribute.

> If you want to know more about these attributes I'll leave some references at the end of this post.

## Changing alpha shadow for specific components
Since you cannot apply these attributes to a layout to affect small part of a screen, there are other 2 attributes that might help you change the shadow transparency of a specific component these are `outlineSpotShadowColor` and `outlineAmbientShadowColor` but keep in mind that **they only work on API level 28 or higher**, with the help of these 2 and setting both `ambientShadowAlpha` and `spotShadowAlpha` to 1 you can change the transparency of the shadow for single components by setting a color that already includes transparency.

You can get it like this, by using a helper function to make the color have opacity:

```
button.outlineAmbientShadowColor = getColorWithAlpha(ContextCompat.getColor(this, R.color.black), 50f)

button.outlineSpotShadowColor = getColorWithAlpha(ContextCompat.getColor(this, R.color.black), 50f)
And of course with this attribute you can change the color of the shadow:
val button2 = findViewById<Button>(R.id.button_test_2)
button2.outlineAmbientShadowColor = getColorWithAlpha(Color.GREEN, 50f)

button2.outlineSpotShadowColor = getColorWithAlpha(Color.GREEN, 50f)
```

This is the result:

![Colored shadow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3c09gkivb18z3apnlb8t.png)

> Always remember that there is an attribute called `stateListAnimator` that controls the shadow of the component, if you ever tried to change the `elevation` of a button and it doesn't work, check the `stateListAnimator` of that button. For example, the definition of `stateListAnimator` for buttons that comes with MaterialTheme (at the the moment of writing this post) sets the enable/base state like this:

```
<!-- Base state (enabled, not pressed) -->
<item android:state_enabled="true">
  <set>
    <objectAnimator
        android:duration="@integer/mtrl_btn_anim_duration_ms"
        android:propertyName="translationZ"
        android:startDelay="@integer/mtrl_btn_anim_delay_ms"
        android:valueTo="@dimen/mtrl_btn_z"
        android:valueType="floatType"
        tools:ignore="UnusedAttribute"/>
    <objectAnimator
        android:duration="0"
        android:propertyName="elevation"
        android:valueTo="@dimen/mtrl_btn_elevation"
        android:valueType="floatType"/>
  </set>
</item>
```

> The main reason for this attribute is to control the animation based on state, like press, hover, enable state. This sets the `elevation` to be `2dp` and `translationZ` to be `0dp`, you can create your own custom state list animator, and can set it to your `buttonStyles`, `materialButtonStyles`, through the app theme or individually to single components. This is not only for buttons there are many components where you can use this attribute.

## Custom shadows

If you really need to change shadows for one specific component only, please take a look at this blog post:

[Simple custom shadow on Android](https://dev.to/mynormeza/simple-custom-shadow-on-android-2eh2)

## Resources & Credits
Shadows seem like a simple subject but there is actually a lot behind it, I'm not going to give deeper explanations but if you want to dig further you can take a look a these blog posts:
[Playing with elevation in Android](https://seebrock3r.medium.com/playing-with-elevation-in-android-91af4f3be596)
[Mastering Shadows in Android](https://medium.com/android-news/mastering-shadows-in-android-e883ad2c9d5b)
[Colors with Alpha](https://magdamiu.com/2017/03/27/android-transparent-colors/)