安卓5.0中android:elevation属性对View有效,但对Button无效?

73

在SDK管理器中的Android 5.0示例中,有一个名为ElevationBasic的示例。它展示了两个View对象:一个圆形和一个正方形。圆形的android:elevation设置为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>
在 Nexus 9 上,运行原始样例代码时,圆圈会出现一个阴影效果: ElevationBasic, As Originally Written 如果我们将小部件类更改为 `Button`,并保留所有其他属性不变,则圆圈上的阴影效果将消失: ElevationBasic, Using a Button 问题如下:
1. 为什么 `android:elevation` 的行为会发生变化?它不能是由于背景而导致的,因为在两种情况下背景都相同。 2. 哪些类支持 `android:elevation`,哪些不支持?例如,将 `View` 或 `Button` 替换为 `TextView` 仍然会给我们带来阴影效果,因此行为上的这种变化并没有在 `TextView` 级别引入,而是在 `Button` 级别引入的。 3. 如昨天的 这个问题中所见,如何在 `Button` 上使用 `android:elevation`?是否需要在主题或其他某些地方添加 `android:allowElevationToWorkAsDocumented="true"` 属性值?

有趣的问题和发现,你能分享测试项目给我们吗? - Rolf ツ
2
@Rolfツ:再次强调,这是Android 5.0示例中的“ElevationBasic”示例,您可以从SDK Manager下载。虽然我没有编写示例,但我已根据问题对“Button”测试进行了修改。 - CommonsWare
我的错,我读得有点太快了 ;) - Rolf ツ
5个回答

143

在Material Design中,按钮的默认样式有一个StateListAnimator来控制android:elevationandroid:translationZ属性。你可以使用android:stateListAnimator属性删除现有的动画或设置自己的动画。

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

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

默认的动画器定义在button_state_list_anim_material.xml中。以下是一个示例,显示启用和按下状态:

<?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>

谢谢!这使得扁平按钮在早期的设备上看起来一样。 - Phuah Yee Keat
1
@CommonsWare 你好,我使用了这个代码,但是没有显示阴影,请帮忙看一下吗? - Pavan
兄弟,你救了我的命啊!通过使用 android:stateListAnimator="@null",我解决了所有关于z-order的问题。 - Gilian
1
那个修改这些值的动画师在很多层面上都是错误的... :( 开发人员完全被蒙在鼓里,不知道为什么按钮具有不同的高程或 z 轴平移。 - bio007

13

根据我的经验,当在Lollipop设备上运行Appcompat v7时,如果在xml元素中设置了个性化的android:background属性(例如颜色或选择器),Button将失去默认功能,如点击涟漪效果、高度和z动画。


这个问题是关于原生Android 5.0实现的,而不是appcompat-v7。谢谢! - CommonsWare
1
如果在Android 5上运行,AppCompat v7会通过平台主题继承Material的样式。 - GPack
同样的问题,如果有人知道答案,那就太好了! - Mino

7
这是因为您手动设置了按钮的背景,这将替换所有其效果。
自版本23.0.0发布以来的AppCompat中,有一个新的Widget.AppCompat.Button.Colored样式,它使用您的主题的colorButtonNormal作为禁用颜色,使用colorAccent作为启用颜色。
    <Button
  ...
  style="@style/Widget.AppCompat.Button.Colored" />

如果您想要不同于指定的颜色,您可以创建一个新的主题并通过android:theme将其应用到按钮上。然后您可以在所有需要相同效果的按钮上使用此主题。

这个问题是关于原生Android 5.0实现的,而不是appcompat-v7。谢谢! - CommonsWare
@Heisenberg 我尝试添加这个功能,但它不会在图像按钮上添加阴影。有什么技巧吗?我已经尝试使用本地ImageButton和AppCompatImageButton。在6.0上测试。 - Rahul Sainani

6

我曾经遇到类似的问题,认为是因为布局充气不当造成的,但实际上只需添加clipToPadding即可解决问题。这必须设置在包含您想要投射阴影的视图的父级ViewGroup中。

... android:clipToPadding="false" ...


1
这个解决方案适用于所有Android API版本。
创建一个阴影@android:drawable/dialog_holo_light_frame,如果你想自定义背景颜色而不是白色,则在阴影的顶部创建一个可自定义颜色的layer-list背景,如下所示。
创建一个单独的可绘制文件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>

使用这个drawable作为背景,像这样

android:background="@drawable/shadow"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接