Buttonのelevationを設定する方法

# はじめに
Android5.0からはView部品に勝手に影がつくよ！という話なので、早速試してみました。
しかし`Button`に`android:elevation="20dp"`なんて設定してみたけれど、思ったような影が描画されません。どうすればいいんだろう？と悩んだ話です。

## スクリーンショット

![BeforeScreenShot.png](https://qiita-image-store.s3.amazonaws.com/0/62406/026e651a-14d1-580b-4f3f-bf428fa2b3f1.png)

## レイアウトXML

```xml:activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="5dp shadow TextView"
        android:background="@android:color/holo_orange_light"
        android:elevation="5dp" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="20dp shadow TextView"
        android:background="@android:color/holo_orange_light"
        android:elevation="20dp"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="5dp shadow Button"
        android:elevation="5dp"
        android:layout_below="@+id/textView"
        android:layout_alignParentStart="true"
        android:layout_alignEnd="@+id/textView" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="20dp shadow Button"
        android:elevation="20dp"
        android:layout_alignTop="@+id/button"
        android:layout_alignStart="@+id/textView2"
        android:layout_alignEnd="@+id/textView2" />

</RelativeLayout>
```

# 原因

こういった時は`Button`のデフォルトのスタイルを確認すれば良いかという事で、`android-21\data\res\values\styles_material.xml`を参照してみると、

```xml:styles_material.xml
    <!-- 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>
```

`<item name="stateListAnimator">@anim/button_state_list_anim_material</item>`というヤツがなんだか怪しい。この`button_state_list_anim_material.xml`を確認すると、

```xml:button_state_list_anim_material.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:state_enabled="true">
        <set>
            <objectAnimator android:propertyName="translationZ"
                            android:duration="@integer/button_pressed_animation_duration"
                            android:valueTo="@dimen/button_pressed_z_material"
                            android:valueType="floatType"/>
            <objectAnimator android:propertyName="elevation"
                            android:duration="0"
                            android:valueTo="@dimen/button_elevation_material"
                            android:valueType="floatType"/>
        </set>
    </item>
    <!-- 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>
    <item>
        <set>
            <objectAnimator android:propertyName="translationZ"
                            android:duration="0"
                            android:valueTo="0"
                            android:valueType="floatType"/>
            <objectAnimator android:propertyName="elevation"
                            android:duration="0"
                            android:valueTo="0"
                            android:valueType="floatType"/>
        </set>
    </item>
</selector>
```

**こ　れ　だ　！**

`objectAnimator`で`elevation`を変更しているため、いくら設定した所でこの値で上書きされてしまっていると思われます。

# 解決策

というわけで、解決策としては`Button`の`StateListAnimator`を設定し直せば良いと思われます。

今回は`button_state_list_anim_material.xml`を丸々コピーして、パラメータだけ変更したStateListAnimatorを新たに作って設定しました。(*※`button_state_list_anim_material_20dp.xml`は省略します*)

## スクリーンショット

![AfterScreenShot.png](https://qiita-image-store.s3.amazonaws.com/0/62406/dccca0ac-1016-50f1-f2c0-3248d76d97f7.png)

## レイアウトXML

```xml:button_state_list_anim_material_5dp.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:state_enabled="true">
        <set>
            <objectAnimator android:propertyName="translationZ"
                            android:duration="100"
                            android:valueTo="2dp"
                            android:valueType="floatType"/>
            <objectAnimator android:propertyName="elevation"
                            android:duration="0"
                            android:valueTo="1dp"
                            android:valueType="floatType"/>
        </set>
    </item>
    <!-- base state -->
    <item android:state_enabled="true">
        <set>
            <objectAnimator android:propertyName="translationZ"
                            android:duration="100"
                            android:valueTo="0"
                            android:startDelay="100"
                            android:valueType="floatType"/>
            <objectAnimator android:propertyName="elevation"
                            android:duration="0"
                            android:valueTo="5dp"
                            android:valueType="floatType" />
        </set>
    </item>
    <item>
        <set>
            <objectAnimator android:propertyName="translationZ"
                            android:duration="0"
                            android:valueTo="0"
                            android:valueType="floatType"/>
            <objectAnimator android:propertyName="elevation"
                            android:duration="0"
                            android:valueTo="0"
                            android:valueType="floatType"/>
        </set>
    </item>
</selector>
```

```xml:activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="5dp shadow TextView"
        android:background="@android:color/holo_orange_light"
        android:elevation="5dp" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="20dp shadow TextView"
        android:background="@android:color/holo_orange_light"
        android:elevation="20dp"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="5dp shadow Button"
        android:elevation="5dp"
        android:layout_below="@+id/textView"
        android:layout_alignParentStart="true"
        android:layout_alignEnd="@+id/textView"
        android:stateListAnimator="@anim/button_state_list_anim_material_5dp"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="20dp shadow Button"
        android:elevation="20dp"
        android:layout_alignTop="@+id/button"
        android:layout_alignStart="@+id/textView2"
        android:layout_alignEnd="@+id/textView2"
        android:stateListAnimator="@anim/button_state_list_anim_material_20dp"/>

</RelativeLayout>
```