web-dev-qa-db-fra.com

Android 5.0 Android: élévation Fonctionne pour View, mais pas Button?

Dans les exemples Android 5.0 du gestionnaire de SDK, il existe l'exemple ElevationBasic. Il montre deux objets View: un cercle et un carré. Le cercle a Android:elevation défini sur 30dp:

<?xml version="1.0" encoding="utf-8"?>
<!--
 Copyright 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.
-->

<FrameLayout 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">
    <View
            Android:id="@+id/floating_shape"
            Android:layout_width="80dp"
            Android:layout_height="80dp"
            Android:layout_marginRight="40dp"
            Android:background="@drawable/shape"
            Android:elevation="30dp"
            Android:layout_gravity="center"/>
    <View
            Android:id="@+id/floating_shape_2"
            Android:layout_width="80dp"
            Android:layout_height="80dp"
            Android:layout_marginLeft="25dp"
            Android:background="@drawable/shape2"
            Android:layout_gravity="center"/>
</FrameLayout>

Sur un Nexus 9, exécutant l'échantillon tel quel, nous obtenons une ombre portée sur le cercle:

ElevationBasic, As Originally Written

Si nous modifions la classe de widget en Button, en laissant tous les autres attributs tels quels, nous perdons l'ombre portée du cercle:

ElevationBasic, Using a Button

Questions:

  1. Pourquoi le comportement Android:elevation est-il en train de changer? Cela ne peut pas être dû au fond, car c'est le même fond dans les deux cas.

  2. Quelles classes supportent Android:elevation et lesquelles ne le font pas? Par exemple, utiliser TextView au lieu de View ou Button nous donne toujours l'ombre portée. Ce changement de comportement n'est donc pas introduit au niveau TextView, mais au niveau Button.

  3. Comme on le voit dans cette question d’hier, comment pouvons-nous obtenir que Android:elevation soit honoré sur une Button? Y at-il une valeur Android:allowElevationToWorkAsDocumented="true" que nous devons mettre dans un thème ou quelque chose?

62
CommonsWare

Le style de bouton par défaut sous Material a un StateListAnimator qui contrôle les propriétés Android:elevation et Android:translationZ. Vous pouvez supprimer l'animateur existant ou définir le vôtre à l'aide de la propriété Android:stateListAnimator.

<Button
    ...
    Android:stateListAnimator="@null" />

<Button
    ...
    Android:stateListAnimator="@anim/my_animator" />

L'animateur par défaut est défini dans button_state_list_anim_material.xml . Voici un exemple montrant les états activé et activé:

<?xml version="1.0" encoding="utf-8"?>
<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>
    ...
</selector>
119
alanv

D'après mon expérience d'Appcompat v7 s'exécutant sur un périphérique Lollipop, Button fonctionne avec les fonctionnalités par défaut telles que l'effet d'entraînement, l'élévation et l'animation z au clic, mais les omet si une propriété Android:background personnalisée (comme couleur ou sélecteur) est définie dans l'élément xml.

13
GPack

En effet, vous définissez manuellement l’arrière-plan du bouton qui remplacera tous ses effets. 

A partir de la version 23.0.0 release de AppCompat , il existe un nouveau style Widget.AppCompat.Button.Colored qui utilise le colorButtonNormal de votre thème pour la couleur désactivée et colorAccent pour la couleur activée .

    <Button
  ...
  style="@style/Widget.AppCompat.Button.Colored" />

Si vous voulez des couleurs différentes de celles spécifiées, vous pouvez créer un nouveau thème et l’appliquer au bouton via Android:theme. Ensuite, vous pouvez utiliser ce thème sur tous vos boutons où vous voulez le même effet.

7
Heisenberg

Je pensais que le problème était dû à une mise en page mal gonflée, mais il est apparu que l'ajout de clipToPadding permettait de résoudre le problème . Ce paramètre devait être défini sur le parent ViewGroup contenant la vue sur laquelle vous souhaitez créer une ombre.

... Android:clipToPadding="false" ...

5
Stefan Bushev

Cette solution fonctionne pour toutes les versions d'API d'Android.

Créez une ombre @Android:drawable/dialog_holo_light_frame & si vous souhaitez personnaliser la couleur de l'arrière-plan plutôt que le blanc, créez un arrière-plan de liste de calques avec une couleur personnalisable au-dessus de l'ombre, comme indiqué ci-dessous.

Créer un fichier dessinable séparé white_background_shadow.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <!--the shadow comes from here-->
    <item
        Android:bottom="0dp"
        Android:drawable="@Android:drawable/dialog_holo_light_frame"
        Android:left="0dp"
        Android:right="0dp"
        Android:top="0dp">

    </item>

    <item
        Android:bottom="0dp"
        Android:left="0dp"
        Android:right="0dp"
        Android:top="0dp">
        <!--whatever you want in the background, here i preferred solid white -->
        <shape Android:shape="rectangle">
            <solid Android:color="@Android:color/white" />

        </shape>
    </item>
</layer-list>

et utiliser ce dessin comme arrière-plan comme celui-ci

Android:background="@drawable/shadow"
0
Shyam Sunder