Google I/O 官方应用中的动效设计
作者:Nick Butcher, Android 设计师 + 开发project师, Google
wx_fmt=png" alt="640?
wx_fmt=png" />
在为 Google I/O 2018 Android 团队工作期间,我们的主要作品之中的一个就是这个官方的应用,同意与会者和远程人员了解会议细节,建立个性化的时间表,并在会场预订座位。我们在应用中构建了很多有趣的动效,并且我们也开源了这个应用的代码,以下我想强调一些这些设计实例,以及一些有趣的实现细节,希望能给大家日常的动效设计带来灵感。
https://mmbiz.qpic.cn/mmbiz_gif/gQOwib4zALd2eghqDtjdJLP6DuIoeKSDrKrsB6vl8ykaWnfTxdPNlNjQLhJlMIa8yst4TwYI1oMZJc50xONEHnw/640?wx_fmt=gif" alt="640?wx_fmt=gif" />
通常我们会在应用中使用 3 种类型的动效:
主动效:用于强化品牌视觉,并带来令人惊喜的视觉焦点
屏幕切换
状态变化
接下来,我想具体介绍一下这些动效的设计细节。
倒计时动画
能够这么说,Google I/O 官方应用的当中一部分作用就是为会议带来兴奋感和期待感。因此,我们在首屏幕和信息页面都显示了大型的倒计时动画。这也是将大会的活动品牌视觉进行呈现的绝佳机会,为应用增添了非常多特色。
wx_fmt=gif" alt="640?
wx_fmt=gif" />
△ 主屏幕抓眼球的倒计时动画
这个动效是由一位动效设计师设计的。并以一系列的 Lottie json 文件交到我们手中:每秒显示一个数字,让它以动效的形式 “in” 然后 “out”。Lottie 格式的文件能够轻松地放入 assets,甚至提供了便利的操作方法,如 setMinAndMaxProgress,它同意我们仅仅播放动效的前半部分或后半部分 (从而仅仅显示动效的进场或出场)。
真正好玩的地方是将多个单独的动画文件布局成总体的倒计时画面。
为此,我们创建了 CountdownView,一个相当复杂的自己定义 ConstraintLayout,当中包括了多个 LottieAnimationViews。在这里,我们创建了一个 Kotlin 托付来封装启动适当的动效。这样我们就能够简单地为每一个应该显示的数字的托付分配一个用来显示的 Int,随后托付就会完毕设置并启动动效。我们扩展了 ObservableProperty,确保我们仅仅在数字更改时才执行动效。我们的动效循环每秒仅仅公布一个可执行状态 (在和视图关联起来的时候)。这个状态计算每一个视图应该显示哪个数字并对托付进行更新。
预约会议
应用的关键操作之中的一个是让与会者预定座位。
因此,我们在会议详情屏幕上的 FAB 中突出显示此操作。
我们觉得应该仅当预定操作在后端成功完毕后再进行提示 (不像那些不太重要的操作。比如 “关注” 一场演讲。我们就差点儿是同步在界面上显示关注成功)。等待来自后端的响应可能须要一些时间。为了这个预定的过程感觉更快捷,我们使用动效图标,表明我们正在对预定进行处理,然后再平滑过渡到成功的状态中。
wx_fmt=gif" />
△ 预定的动画。有展示后端操作的动画过程
这个图标须要反映的状态非常复杂:会议可能是可预订的。可能已经预留了座位,假设座位已满。则可能产生等候名单,他们也可能出如今等待列表上。或是在会议即将開始时预约功能被禁用了。
这会导致应用须要显示多种动效以代表各种不同的状态。为了简化这些转场效果。我们决定始终显示 “后端操作” 状态,也就是上面动画中的沙漏。
因此。每次动效切换实际上都是成对的:状态 1 → 后端操作 & 后端操作 → 状态 2。这样就简化了非常多事情 (不然您能够想象可能出现的排列组合会有多少)。接下来我们使用 shapeshifter 构建了全部这些动效。
为了显示这些动效,我们使用了自己定义视图和 AnimatedStateListDrawable (ASLD)。假设你还没实用过 ASLD,我们简介一下:正如其名,它是动效版的 StateListDrawable,让你不仅能够为每一个状态提供不同的 Drawable,还能够提供过渡状态之间的转场 (以 AnimatedVectorDrawable 或 AnimationDrawable 的形式)。
我们创建了一个自己定义视图来支持这些自己定义的预定状态。
视图提供一些标准状态,如已按下或已选中。相同,您也能够定义自己的状态。并依据状态显示不同的 Drawable。我们自行定义了 state_reservable,state_reserved 等,随后我们会再为这些不同的状态创建一个枚举,封装视图状态以及不论什么相关的属性,如相关的内容描写叙述。
然后,我们的业务逻辑能够简单地从视图上的这个枚举中设置适当的值 (通过数据绑定)。这将更新 Drawable 的状态,然后通过 ASLD 启动动效。自己定义状态和 AnimatedStateListDrawable 是实现这一点的一种巧妙方法,将多个状态保留在声明层中。从而产生最少的视图代码。
演讲者动效
很多屏幕间的转场动画都能够直接用标准窗体动效。我们另辟蹊径的地方是。前往演讲者介绍信息屏幕的转场效果。例如以下图,演讲者头像在演讲信息和演讲者信息两个屏幕之间共享,是典型的共享元素转场动画,这样也有助于理解前后两个屏幕间的内容关联。
△ 演讲者头像在两个屏幕间共享
这里是一个非常标准的共享元素转换,在 ImageView 上使用了 ChangeBounds 和 ArcMotion 类。
更有意思的是。启动这个转场效果本身也会纳入我们的导航设计/开发模式中来。大体上讲,这样的模式将输入事件 (如点击一位演讲者) 与导航事件分离,让 ViewModel 来负责怎样响应输入。在这样的情况下,这样的解耦意味着,ViewModel 将会暴露出 Events 的 LiveData,它仅仅知道须要导航到哪个 ID 的演讲者。启动共享元素转场效果须要共享 View。而在这一瞬间这个 View 还没有。
我们解决问题的方式是,在绑定时将演讲者的 ID 作为标签存储在视图上,以便稍后当我们须要导航到特定的演讲者细节屏幕时检索该视图。
过滤器
会议应用的核心功能之中的一个是帮助用户从很多会议中过滤出感兴趣的那些。每一个话题都有一个与之相关的颜色。以便识别。我们收到的设计方案基于 “Chip” 动画,便于用户与各个话题进行操作。
https://mmbiz.qpic.cn/mmbiz_gif/gQOwib4zALd2eghqDtjdJLP6DuIoeKSDrvW2sscD3h9hmpicKLZNFdjnZEib2T0W9y2bcibKoYmKBETdBOJcpNQWxQ/640?wx_fmt=gif" alt="640?wx_fmt=gif" />
△ Chip 列表非常适合用来挑选感兴趣的话题
Material Components 里提供了默认的 Chip 控件,但我们决定使用自己定义视图。以便更好地控制各个状态的显示内容和动效。
我们使用 canvas 进行画图并使用 StaticLayout 来显示文本。该视图具有单一的 progress 属性,即 0 - 未选中 / 1 - 已选中。在状态切换的时候,我们会同一时候改动视图中的显示元素。并使用线性插值来决定每一帧的形状和颜色。
最初在实现这个控件时,我让视图实现了 Checkable 接口,并在 setChecked 方法被调用来给状态赋新值的时候启动动效。只是当我们在 RecyclerView 中显示多个过滤器时。会出现用户的操作触发的动效和数据绑定触发的动效冲突的情况。为了解决问题,我们单独提供了一个触发动效的方法来避免这样的冲突。
此外,当我们刚刚给应用里引入这个动画效果时。我们发现它有丢帧。是我的动效代码有问题吗?这些控件位于一个 BottomSheet 中,且被放置在会议日程安排画面的前面。
当过滤器里的值被改动时。我们会执行过滤会议形成的业务逻辑,并且更新关注列表里的关注内容,这些看来都没什么问题。后来经过排查,我们确定问题在于。当过滤器里的内容被改动的时候。负责显示日程的 RecyclerViews 的 ViewPager 尽职尽责地启动了,并依据新提供的数据进行了更新。
这导致很多视图出现了由于内容添加而“膨胀”的现象。更由于这个视图内容的添加而触发了自适应布局的逻辑,来又一次渲染当中的内容。
全部的这些逻辑都是自己主动的,也没问题……除了会撑爆我们的刷新率。但关注列表事实上在过滤器的 “后面” (被遮住了),于是我们决定延迟执行关注列表里的内容更新 (直到过滤器里的值都被确定,且动效開始执行时才更新),我们牺牲了一些实现的复杂性。换取了更加顺畅的用户体验。最初我使用 postDelayed 实现它,但这导致了 UI 測试时出现故障。
于是,我们改动了启动动效的方法。同意它接受一个 lambda 表达式。这样一来,我们就能在保持用户操作的动效和高效的測试之间找到一个平衡。
一起动起来吧!
总的来说。我觉得动效确实有助于改善应用的体验,以及提升品牌表现力。
希望这篇文章能让您明确我们在各个环节使用动效的动机,以及具体实现它们的做法。更重要的是,我们希望您的应用中也能出现丰富多彩的动效,在抓人眼球的同一时候也能非常好地表达品牌信息和交互意图。
wx_fmt=gif" />
推荐阅读:
· __biz=MzAwODY4OTk2Mg==&mid=2652047165&idx=1&sn=c84d1061ab83744f25f5d2793bc49358&chksm=808ca778b7fb2e6ee11510020f219185bb120e65c31fef6df7060e5efb7f1f7d067af79abe2c&scene=21#wechat_redirect" rel="nofollow">
https://mmbiz.qpic.cn/mmbiz_gif/gQOwib4zALd25L5EssHcTvSLKkt3Lv7H0d7rD42zgzRjiaCNFgH2RakJof5zPEemFKrb2pqSXovjL1XFch4z91CA/640?wx_fmt=gif" alt="640?
wx_fmt=gif" />
Google I/O 官方应用中的动效设计的更多相关文章
- 前端读者 | 前端用户体验-UI动效设计
本文来自互联网 @羯瑞 整理 UI动效现如今在 APP 和网页中几乎已经成为了基本的组成部分,经过仔细打磨的 UI动效对于整个界面的提升是显著的. 动效呈现出状态切换的过程,展现了元素之间的逻辑关系, ...
- iOS 停止不必要的UI动效设计
http://www.cocoachina.com/design/20151124/14400.html 前言:这篇短文将会探讨UI设计中动画的过度使用,并将其与早期的视觉设计进行对比,提出一些对于有 ...
- 拒绝枯燥,有意思的 Loading 页面动效设计
互联网时代,网络“提速”日益频繁,人们打开Web或软件的速度越来越快,一般页面缓冲和加载地过程也是几不可查.然而,在某些情况下,例如软件急需加载大量页面,首页急需加载大量内容,用户下载文件过大,甚至是 ...
- Principle如何制作动效设计?简单易学的Principle动效设计教程
Principle for Mac是一款新开发的交互设计软件.相比 Pixate 更容易上手,界面类似 Sketch 等做图软件,思路有点像用 Keynote 做动画,更「可视化」一些. 如果您还没有 ...
- 很好的UI动效设计参考
toolBar下拉:
- 新版MATERIAL DESIGN 官方动效指南(一)
Google 刚发布了新版Material Design 官方动效指南,全文包括三个部分:为什么说动效很重要?如何制作优秀的Material Design动效及转场动画,动效的意义.新鲜热辣收好不谢! ...
- 新版MATERIAL DESIGN 官方动效指南(二)
继上一篇,本文继续第二部分,从动效的速度.动态持续时间.通用持续时间和缓动曲线4个部分,教你创建平滑一致的Material Design 动效.再系统的干货都比不上官方的动效指南,西瓜就在这,赶紧来捡 ...
- Web动效研究与实践
随着CSS3和HTML5的发展,越来越多狂拽炫酷叼炸天的动效在网页设计上遍地开花,根据最新的浏览器市场份额报告,IE6的份额已经降到了5.21%,这简直是一个喜大普奔的消息,做动效可以完全不care低 ...
- android动效开篇
大神博客:http://blog.csdn.net/tianjian4592/article/details/44155147 在现在的Android App开发中,动效越来越受到产品和设计师同学的重 ...
随机推荐
- 最长不下降子序列nlogn
b[i]表示长度为i的最长不下降子序列的最小末尾元素的值显然它是单调递增的,满足二分性质,然后就可以愉快地二分啦. #include<iostream> #include<cstdi ...
- linux学习笔记 yum 在线管理软件包
-y 如果yum在工作过程中需要使用者响应.这个参数可以直接回答yes #yum list 列出资源库中所有可安装或者可更新的rpm包 #yum perl 列出为perl的包 #yum perl* ...
- MySQL安装目录修改
- XamarinEssentials教程清空键值
XamarinEssentials教程清空键值 Preferences类的Clear()方法可以清空所有的键和值.该方法有两种形式,下面依次进行介绍. (1)Clear()方法的语法形式如下: pub ...
- Java并发编程(十三)-- 线程池
什么是线程池? 线程池就是以一个或多个线程循环执行多个应用逻辑的线程集合. 为什么用线程池? 创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率 例如: 记创建线程消耗时 ...
- JS简单实现滚动自动加载新内容(懒加载)
加载源 // 这里存后台发来的数据 var galleryList = [ { src: "./images/1.jpeg", desc: "11111" }, ...
- [NOI2014]起床困难综合征
Description: 有n扇门,每扇门上有一个位运算符(&,|,^) 和一个权值,要求合理的选择一个不超过m的数,使其按顺序经过这些门的运算后最大 Hint: \(n \le 10^5\) ...
- 在npm上发布一个自己的包
1.首先你要在npm上创建一个账号,这里需要输入邮箱的,注意激活邮箱否则无法publish自己的包 2.在本地创建一个文件夹,输入npm init初始化项目,这里是我使用npm init创建的pack ...
- python系统编程(七)
多线程-共享全局变量 from threading import Thread import time g_num = 100 def work1(): global g_num for i in r ...
- Nginx (LNMP+https)
单向认证与双向认证的概念 什么是单向认证 单项认证就是比如你有个密码用户名然后和服务器上的用户信息进行比对一致的话你们就可以建立连接. 什么是双向认证 SSL的双向认证就是客户端要获取服务端的证书,检 ...