聊聊 MD 设计里,阴影的那些事儿(一)

当你的设计师要求你在某个 View 上增加阴影效果,那你只需要认真阅读本文,阴影的问题就不再是问题。

全文太长了,我拆分成三篇来发布,今天是第一篇。

一、前言

设计师的世界,与常人不同,有时候想要扁平化的风格,有时候又想要拟物化的风格。而在 Material Design 出来之后,为 UI 元素引入了高度的概念,它可以让某个元素更为突出,显示出它的重要性,更让人有点击的欲望。

在拟物化的设计里,UI 元素的高度,反应在效果上,就是在边框上有阴影的效果,感觉它是距离底部有一个层次的关系。在 Material Design 的设计中,也大量的使用了 阴影 的效果,例如:FloatingActionButton、CardView 这些控件,都是默认支持阴影效果的。

如果你想了解 Material Design 中,更多关于阴影的设计,可以查阅官方文档。

https://material.io/guidelines/material-design/elevation-shadows.html?hl=zh-cn

接下来,我们就来介绍一下,在 Android 的不同版本中,使用不同的方式,去实现阴影的效果。

先来看看实现的效果,虽然多,但是它们实现的方法都不相同。

二、阴影的效果

在拟物化的世界里,阴影主要是对三维空间中的 Z 属性进行操作。下面是官网的介绍。

由 Z 属性所表示的视图高度将决定其阴影的视觉外观:拥有较高 Z 值的视图将投射更大且更柔和的阴影。 拥有较高 Z 值的视图将挡住拥有较低 Z 值的视图;不过视图的 Z 值并不影响视图的大小。

阴影是由提升的视图的父项所绘制,因此将受到标准视图裁剪的影响,而在默认情况下裁剪将由父项执行。

https://developer.android.com/training/material/shadows-clipping.html?hl=zh-cn#Elevation

静态效果如下:

再加上,动态的效果应该更能让你对阴影有所理解。

三、使用标准 Api

Material Design 首次出现在 Android 5.0 中,之后又有一些 Support 包,让更低的版本,对 Material Design 进行支持。

而在 Api Level 21 之中,增加了两个属性 :

  • elevation:高度,用于提升 UI 元素高度的属性。

  • translationZ:Z 轴的变换效果。

这两个属性,有对应的 xml 属性和 setXxx() 方法,而 Z 轴的改变,主要是由这两个属性决定的。

Z = elevation + translationZ

所以,如果你的 App 的 minSdkVersion 就是 21 的话,直接使用这两个属性是最优的解决办法。

3.1 elevation 属性

elevation 属性,主要用于给 View 增加一个高度,可以直接被加在 View 控件上,呈现在界面上,就是一个带阴影的效果。

在 layout-xml 布局中,可以通过 android:elevation 属性来设置,而在 Java 代码中,通过 View.setElevation() 方法来使用它。

直接使用 elevation 属性设置即可,它接收一个高度的参数,只需要按我们的需要配置即可。

需要注意的是,View 的阴影一定是需要有背景的 View 在视觉上增高之后,投射出来的。也就是类似于打光的阴影效果。简单来说,就是需要为 View 设置一个 Background,可以使用 android:background 属性或者 View.setBackground() 方法设置,否者 elevation 的属性设置将无效。这里的 Background 只需要设置一个 Drawable 即可,你当然也可以选择一个图片或者一个纯色的 <shape/> 了。

下面来看看 elevation 属性的效果:

往深里再看看 elevation 属性的实现方式。

它最终还是调用的 mRenderNode 去做的操作,在追踪下去,就会发现它底层是用的 native 的方法实现的,所以应该不是我们最开始所理解的用 2D 的渐变模拟阴影的效果。

3.2 translationZ 属性

translationZ 属性,主要用于给 View 增加一个在 Z 轴上的变换效果。它和 elevation 配合起来,就是一个一加一等于二的效果。也可以用于设置 View 的高度。

在 layout-xml 布局中,可以通过 android:translationZ 属性来设置它,而在 Java 代码中,可以通过 View.setTranslationZ() 方法来使用它。

一般来说,我们可以直接使用 android:translationZ 属性来设置 View,当你配合 android:elevation 属性一起使用的时候,它们对 View 的高度是累加的,当然你也可以只使用其中一个属性。

而看到 translationZ 这样的属性,很轻易就联想到了 translationX 和 translationY 了,它们实际上就是不同维度的设置,思路上很像,但是原理不同。对 X、Y 轴的操作并没有 Api Level 的限制,这一点需要清楚。

和 elevation 属性一样,translationZ 也是需要配合 Background 的设置才会生效的,这个应该不难理解。

下面我们来看看 translationZ 属性的设置效果:

使用 translationZ 属性实现的效果,看着和 elevation 的效果很像,而它内部也是依赖于 mRenderNode 去做的实现,但是方法并不一样。

3.3 ViewCompat 来兼容 Api

前面就已经提到,当你的 minSdkVersion 达不到 elevation 和 translationZ 这两个 Api 的要求,设置为 Api Level 21(Android 5.0) 以下。你在使用这两个属性的时候,会给你提示 Warning,如果打包的时候有 Lint 的校验,也是会提示并且导致打包失败的。

不过看提示你也能发现到底是什么问题:

Attribute elevation is only used in API level 21 and higher

如果已经明确在低于 Api Level 21 之下的版本,都不加阴影的效果,你可以在布局中,使用 tools:targetApi="lollipop" 来消除这个 Warning。

如果你是在 Java 代码中,为 View 动态设置 elevation 或者 translationZ 属性的话,除了使用 Build.VERSION_CODES.LOLLIPOP 判断之外,还可以使用 ViewCompat 这个 Android 为我们提供的标准的 View 兼容类,当然,这里推荐使用 ViewCompat

既然要用到 ViewCompat 的话,那我们来看看它的原理是什么。

在 ViewCompat 中,会有很多个实现了 ViewCompatBaseImpl 的接口类,它们分别对应了不同的 Api Level ,会在静态代码块中,根据当前运行设备的 Api Level ,做不同的实现。而这些,都是高版本继承低版本的实现,来达到继承兼容的效果。

ViewCompatBaseImpl 这个接口中,定义了很多关于 View 的操作 Api ,这些 Api 都是存在不同的 Api 版本限制的。

在 Api Level 21 中,本身就已经支持了这两个属性,也就不存在兼容性的问题了,所以它其中会直接调用 setElevation()setTranslationZ() 方法。

那么,我们只需要关心 Api Level 21 以下的实现。通常来说,我们做兼容处理,一个方案就是在低版本上,使用一些只在低版本上存在 Api,来对高版本的效果进行模拟;另外一个方案就是放弃低版本,完全对它不做任何处理。

我们来看看 ViewCompat 是对 Elevation 是选用的那个方案。其实 Api Level 21 之下,都没有对这两个属性的操作方法,做任何的处理,你一路追踪下去可以追踪到 ViewCompatBaseImpl 。

从这里可以看出,ViewCompat 没有对这两个方法做任何的兼容,在低版本上,没有做任何的操作,这也导致了你如果使用 ViewCompat 的话,在低版本上是不会有阴影的效果的。没有就是没有,这里就不再单独展示了。

那看看使用 ViewCompat 在高版本上的效果图,其实和之前的也没啥区别,不过摆在一起看更清晰一些。

3.4 标准 Api 小结

到现在你也能看到,如果不在意 Api level 的话,你完全可以使用 android:elevationandroid:translationZ 两个属性来做的阴影的效果,效果也是非常好的,而且它的阴影实际上是不占用 View 的布局大小的,它会在原本的布局之外,向外扩散,所以也不会影响 View 本身大小的视觉效果。

不过它也有缺陷,你只能通过设定这两个属性来调整阴影的大小,没办法做到精确掌控,并且无法修改阴影的颜色。

最新的 Android 版本市场占有率,你可以在这个网站上查到。

https://developer.android.com/about/dashboards/index.html?hl=zh-cn

截止到本文编写的时候,低于 5.0 的版本,差不多在 20% 左右,是否对这部分用户,放弃阴影的效果,取决于你的产品和设计师。

如果你需要兼容低版本的设备,后面介绍的一些方法,都可以做到,继续看下期文章吧。

今天在承香墨影公众号的后台,回复『成长』。我会送你一些我整理的学习资料,包含:Android反编译、算法、设计模式、Web项目源码。

推荐阅读:

点赞或者分享吧~

点击『阅读原文』查看更多精彩内容

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值