彻底理解 Android 中的阴影
如果我们想创造更好的 Android App,我相信我们需要遵循 Material Design 的设计规范。一般而言,Material Design 是一个包含光线,材质和投影的三维环境。如果我们想要在 App 的开发过程中,跟随 Material Design 的设计原则,那么理解 光 与 阴影 就显得尤为重要了。
我将尝试解释本文中的以下主题。
- Android 中的 3D
- 深度(Depth)
- Z 轴,Elevation 和 Translation Z。
- 光源
- 按钮状态(按下和静止)
- Outline
- 自定义的 ViewOutlineProvider
在深入到阴影和光线之前,我想告诉你我们的真实环境什么?
什么是 3D?
真实的物质环境,是一个三维空间,这意味着所有的物体对象都有 X、Y 和 Z 维度。Z轴与显示器的平面垂直对齐,正 Z 轴朝向观察者延伸。在 Material Design 的世界里,每个物体都有 1dp 的厚度。
Android 的 Depth
Material Design 不同于其他的设计指南,因为它增加了 Depth(深度)的概念。而 Depth 在真实的视觉中,有重要的意义。
我们可以认为我们桌子上有一层纸,如果我们再贴一张纸,我们的眼睛会觉得它有一个深度。
让我们通过 Material Design 的应用截图来想象它。
让我们来看看屏幕上的各个元素。
- 屏幕(表层 - 深度为 0 )
- CardViews
- App UI 布局
- 浮动动作按钮(Floating Action Button)
这里面,每个元素都在另一个元素之上。CardView 可以滚动,所以我们可以说第一层是可滚动的内容,第二层是 AppBar 布局,第三层(顶层)是浮动动作按钮。
那么,我们如何定义层级?我们如何让用户感受到深度?答案是: Z 轴。
Android 中的 Z 值是什么?
View 的 Z 值有两个组成部分:
- Elevation:高度,一个静态值。
- Translation Z:Z轴变动值,用于动画的动态值。
我总是在想 Elevation 和 Translation Z 有什么区别。
Elevation 是静态的,所以你最好不要动态的去改变他。如果你想在 Z 轴上做动画的效果(如按下态或者静止态),你需要使用 Translation Z 属性。
Translation Z 是动态的,当你创建一个空白项目,并在其中增加一个按钮的时候,当你按下它你将会看到阴影变大了。实际上 Elevation 并没有变化,而是 Translation Z 属性在变化。这是 Android 使用默认的状态列表动画,更改 Z 属性。
Z Vaue = Elevation + TranslationZ
如果我们改变两个具有 Z 值的 View,让它们相交。Android如何处理屏幕上的层级?让我用一个我设计的图表向你展示。
另外一个问题,我们如何看到物体的影子?我们是需要一个阴影吗?不是的,我们是需要一个光源。
Android 中的光源是什么?
其实问题不在于是什么?而是在哪里。
在现实中,如果我们手持一个手电筒照桌子上的物体(从它的顶部),阴影的长度会缩短,当你降低它的时候,阴影的长度会增加。
那么在 Android 的 Material Design 中,光源在哪里?在顶部?还是有角度的?经过一番研究,我发现这个现象。
Android 中存在两个光源,顶部那个是关键的光源,而另一个是环境光源,我们看到的阴影实际上是这两个光源的组合。
让我们看看显示的效果。
在 Android 中,我们有很多小部件。按钮、CardView、对话框,抽屉等所有这些都是视图。如果有一个光源,我们就有阴影。那么我们如何在Android中决定 Z 值呢?Material Design 是如何规定这些的?
有一个示意图来反映这种情况。
静止或者按下
正如我之前提到的,在 Android Framework 中,一些动画是为小部件而实现的。如果你在布局中放置浮动操作按钮,默认情况下它将具有 6dp 的 Elevation。但是你会注意到当你按下按钮时,FAB 的 Elevation 将会提高到12 dp。
让我告诉你,在这个过程中发生了什么。
其实FAB有 6dp 的 Elevation。当您按下按钮时,translationZ 值开始增加。ViewPropertyAnimator 通过将 translationZ 值从 0dp 更改为 6dp 来 让视图动起来。如果你释放按钮,ViewPropertyAnimator 播放动画,将 translationZ 从 6dp 变到 0dp。你可以为你的视图创建自定义状态列表动画,并将其添加到你的视图上。
我们来看一下这个过程的流程图。
阴影的秘密:Outline
Outline 是一个属于 android.graphic 下的类,看看它的文档都说了什么
定义一个简单的形状,用于图形的边界区域。
可以为 View 计算,也可以由 Drawable 计算,以驱动由视图投射的阴影的形状,或剪裁视图的内容。
每个 View 都有默认的轮廓以显示其阴影。如果我们创建一个可绘制的自定义形状,其轮廓将根据其形状在内部进行计算。所以,如果我们画圆,轮廓将会是圆的。如果我们绘制矩形,轮廓将是矩形。
总而言之,有一个 Outlin 可以让你以不可见的方式看到这个效果。但是,如果我想创建一个自定义的视图,并动态地改变它的边界呢?Android 会为我的自定义视图提供了 Outline 吗?
Android 当然为我们提供了自定义 Outline 的办法,那就是 : ViewOutlineProvider。
什么是 ViewOutlineProvider
在我最近的开源的 ScalingLayout 库中,我没有对自定义视图实现阴影效果。我以为这是非常漂亮,没有影子。但要记住 Material Design 的基础知识,3D,Depth,Z-Value。
在这个动画中,我们可能无法确定那些地方是可以被点击的,而且缩放布局中并没有阴影。
接下来我们为自定义的视图提供动态的轮廓。
public class ScalingLayoutOutlineProvider extends ViewOutlineProvider {
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(0, 0, width, height, radius);
}
}
public class ScalingLayout extends FrameLayout {
//...
viewOutline = new ScalingLayoutOutlineProvider(w, h, currentRadius);
setOutlineProvider(viewOutline);
//..
}
这样,我们就为自定义的 View 增加了高度的支持。
更多有关于 ViewOutlineProvider 的使用中,被简化的一些基础知识,你可以在 ScalingLayout 中找到细节。
作者 | Mert Şimşek
翻译 | 承香墨影
授权 承香墨影 翻译并发布
今天在公众号后台回复成长『成长』,将会得到我整理的一些学习资料,也能回复『加群』,一起学习进步。
推荐阅读:
- 站在Android开发的角度,聊聊Airbnb的Lottie
- 这些工具,让你写博客的时候,只需要专注写作!
- 找了一天找不到 Bug ? 试试 Git 的二分法吧!!!
- 如何更精准的在 Github 上搜索开源库?你需要这些技巧!
- Android 开发,遇上 Emoji 头疼吗?
彻底理解 Android 中的阴影的更多相关文章
- 深入理解Android中View
文章目录 [隐藏] 一.View是什么? 二.View创建的一个概述: 三.View的标志(Flag)系统 四.MeasureSpec 五.几个重要方法简介 5.1 onFinishInflate ...
- 【转】Android菜单详解——理解android中的Menu--不错
原文网址:http://www.cnblogs.com/qingblog/archive/2012/06/08/2541709.html 前言 今天看了pro android 3中menu这一章,对A ...
- Android菜单详解(一)——理解android中的Menu
前言 今天看了pro android 3中menu这一章,对Android的整个menu体系有了进一步的了解,故整理下笔记与大家分享. PS:强烈推荐<Pro Android 3>,是我至 ...
- 深入理解Android中ViewGroup
文章目录 [隐藏] 一.ViewGroup是什么? 二.ViewGroup这个容器 2.1 添加View的算法 2.1.1 我们先来分析addViewInner方法: 2.1.2 addInArr ...
- 理解android中ListFragment和Loader
一直以来不知Android中Loader怎么用,今天晚上特意花了时间来研究,算是基本上搞明白了,现在把相关的注释和代码发出来,以便笔记和给网友一个参考,错误之处还望大家给我留言,共同进步,这个例子采用 ...
- 一个demo让你彻底理解Android中触摸事件的分发
注:本文涉及的demo的地址:https://github.com/absfree/TouchDispatch 1. 触摸动作及事件序列 (1)触摸事件的动作 触摸动作一共有三种:ACTION_DOW ...
- 绝对让你理解Android中的Context
这个问题是StackOverFlow上面一个热门的问题What is Context in Android? 整理这篇文章的目的是Context确实是一个非常抽象的东西.我们在项目中随手都会用到它,但 ...
- 理解Android中的注解与反射
反射 Java反射(Reflection)定义 Java反射机制是指在运行状态中 对于任意一个类,都能知道这个类的所有属性和方法:对于任何一个对象,都能够调用它的任何一个方法和属性: 这样动态获取新的 ...
- 【转】深入理解Android中的SharedPreferences
SharedPreferences作为Android中数据存储方式的一种,我们经常会用到,它适合用来保存那些少量的数据,特别是键值对数据,比如配置信息,登录信息等.不过要想做到正确使用SharedPr ...
随机推荐
- ngRx 官方示例分析 - 1. 介绍
ngRx 的官方示例演示了在具体的场景中,如何使用 ngRx 管理应用的状态. 示例介绍 示例允许用户通过查询 google 的 book API 来查询图书,并保存自己的精选书籍列表. 菜单有两 ...
- sql语句添加删除外键及其约束
--删除外键 ALTER TABLE t_base_role_module DROP CONSTRAINT fk_t_base_role_module_t_base_defined_url; --增加 ...
- ScrollView(RecyclerView等)为什么会自动滚动原理分析,还有阻止自动滑动的解决方案
引言,有一天我在调试一个界面,xml布局里面包含Scroll View,里面嵌套了recyclerView的时候,界面一进去,就自动滚动到了recyclerView的那部分,百思不得其解,上网查了好多 ...
- linux下建ftp用户,并限制用户访问路径[转]
目的是:在linux系统上建立ftp用户,并限制其通过ftp访问时,只能访问用户主目录:其主目录显示路径也是“/”,看不到上级目录. 例如,我要建立用户usertest,密码为usertest ...
- windows7 设定开关机事件
动记录开关机的技能你知道吗? 下面跟我来设定一下记录电脑的开关机时间吧,工作常常会用到的. 在""我的电脑"右击=>管理=>系统工具=>时间查看器=&g ...
- 微信屏蔽js分享、复制链接
页面内引入js(不放在页面内部不起作用) $(function(){ function onBridgeReady() { WeixinJSBridge.call('hideOptionMenu'); ...
- maven系列--maven目录
我们在玩maven,首先就是利用maven来管理我们的项目.其实maven并不难,它无非是一种目录结构.所以在本系列开始之前,我们要细致的了解下maven的目录,其实也就是maven的约定. 约定优于 ...
- linkin大话设计模式--模板方法模式
linkin大话设计模式--模板方法模式 准备一个抽象类,将部分逻辑以具体方法的形式实现,然后申明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不 ...
- css中 padding属性的数值赋予顺序为
4种可能的情况,举例说明:padding:10px; 四个内边距都是10pxpadding:5px 10px; 上下5px 左右10pxpadding:5px 10px 15px; 上5px 右10p ...
- matlab判断文件或文件夹是否存在
当前目录中包含以下文件及文件夹: startup.m win64/ … 判断当前目录中是否存在startup.m文件 if ~exist('startup.m','file')==0 error ...