0

I've been struggling with this for too long. I created a new Android project with a basic Activity, which comes with a button on a Fragment. My layout looks like this:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fff"
    android:clipToPadding="false"
    android:padding="20dp"
    tools:context=".FirstFragment">

    <TextView
        android:id="@+id/button_first"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/buttonback"
        android:elevation="10dp"
        android:paddingStart="20dp"
        android:paddingEnd="20dp"
        android:text="Text"
        android:textColor="@color/black"
        android:translationZ="5dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button_other"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:background="@drawable/buttonback"
        android:elevation="10dp"
        android:text="Button"
        android:textColor="@color/black"
        android:translationZ="5dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/button_first" />
</androidx.constraintlayout.widget.ConstraintLayout>

And whatever I try the button drop shadow never changes. Elevation, TranslationZ, changing themes...always just a slightly visible outline around the button. I've tried everything posted on SO, like this popular post, and nothing works or alters the drop shadow. It seems like Google is FORCING buttons to not have drop shadows because textView drop shadows DO work. Here are 2 views a textview and a button with the same attributes:

enter image description here

The textview is on top, and has the drop shadow I want. So what's the trick? How can I get the same drop shadow on a button? BTW, when I press the button is does appear to have a drop shadow, but I want the button to have the drop shadow when NOT pressed.

PS. Annoyingly the button drop shadow appears in the layout design editor...but not when compiled and running on a device.

szaske
  • 1,419
  • 13
  • 23
  • @WhatAJerk, That post suggests creating a fake shadow object and placing it behind the button. I cannot believe this would be the correct solution. That would not look good when animated or when the button is pressed – szaske May 14 '21 at 16:02

1 Answers1

0

Looks like I was correct, Google does treat buttons differently. The issue is an attribute called stateListAnimator. It appears to override elevation and translationZ making them useless. You can solve the problem by adding this line to your button XML:

android:stateListAnimator="@null"

then your elevation and translationZ attributes will work correctly. A better solution though it to create your own stateListAnimator. To do this create a directory called animator under your res folder and then add a new animator resource file to it called button_with_shadow.xml. Here's a sample that works well:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_enabled="true"
        android:state_pressed="true">
        <set>
            <objectAnimator
                android:duration="50"
                android:propertyName="translationZ"
                android:valueTo="2dp"
                android:valueType="floatType" />
            <objectAnimator
                android:duration="50"
                android:propertyName="textSize"
                android:valueFrom="15sp"
                android:valueTo="14sp"
                android:valueType="floatType" />
        </set>
    </item>
    <item
        android:state_enabled="true"
        android:state_pressed="false">
        <set>
            <objectAnimator
                android:duration="50"
                android:propertyName="translationZ"
                android:valueTo="10dp"
                android:valueType="floatType" />
            <objectAnimator
                android:duration="50"
                android:propertyName="textSize"
                android:valueFrom="14sp"
                android:valueTo="15sp"
                android:valueType="floatType" />
        </set>
    </item>
    <item android:state_enabled="false">
        <set>
            <objectAnimator
                android:duration="50"
                android:propertyName="translationZ"
                android:valueTo="1dp"
                android:valueType="floatType" />
            <objectAnimator
                android:duration="50"
                android:propertyName="textSize"
                android:valueFrom="15sp"
                android:valueTo="14sp"
                android:valueType="floatType" />
        </set>
    </item>
</selector>

It should be fairly easy to see what's happening here. Here's by button XML:

    <Button
        android:id="@+id/button_other"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:paddingStart="30dp"
        android:paddingEnd="30dp"
        android:textSize="15sp"
        android:background="@drawable/buttonback"
        android:stateListAnimator="@animator/button_with_shadow"
        android:text="Button"
        android:textColor="@color/black"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/myText" />
szaske
  • 1,419
  • 13
  • 23