Framer学习备忘手册:类和模块的应用

写在前面的话

Framer用来上手原型的优点不必多说,缺点对设计师来说可能就是coffeescript的学习曲线比较陡,和样式、结构、事件代码分离的常规界面开发不同,Framer里面所有代码全部掺杂在一起,相当不利于整理和组织。虽然注释和代码折叠等技巧可以一定程度增加代码的可读性,但到真正进阶到利用class和module去管理项目的代码的时候,才能从本质上解决复杂项目代码冗余不利于阅读管理等问题。下面的文章分享自Framer社区的一名UI设计师Tess Gadd,通过她分享总结可以帮助我们改进Framer工作流。原文链接点击这里查看。

Continue reading “Framer学习备忘手册:类和模块的应用”

利用Haiku在项目中添加Motion动效

文章分享自Nad Chishtie,点击查看原文

现代数字产品的一个共同设计目标是创造惊喜和取悦用户,而Motion设计可以成为你的武器库中最强大的那个工具。有趣的加载动画、舒适的反馈和恰当的转场动画引导,都是提升用户体验的好方法。

针对设计师如何在动效设计构建中找到最恰当的表现形式,Paul Stamatiou为我们做了很好的总结:

如果你是一个设计师,请学习运用Motion设计技巧。60fps的动画,你需要在Mock A和Mock B之间设计58帧。

——Paul Stamatiou@Stammy

遗憾的是,大多数现代设计工具和工作流程并不能够让设计者真正设计出这58帧。

当今流行的工作流往往围绕着创建一次性原型,用于与开发人员进行交流,然后后者费力地利用代码艰难地再现直到调试到视觉和使用上的最佳效果。

这不仅浪费时间和资源,而且过程是如此的疲惫不堪,甚至经验丰富的设计师和开发人员最终都在“足够好”的实现层面上止步了。如果他们想在尝试完一个概念之后继续迭代他们的设计,他们又得从头开始。

与众不同的Haiku

 

 

在Haiku中编写的所有内容都是随时可发布的成品,一旦与代码库集成,你就可以继续在你的设计上进行迭代。少了一些没有必要承接转换。

 

用时间&空间两个维度思考物体运动

在我们撸起袖子使用Haiku之前,一个很有效的方法就是通过像动画师一样,用时间空间的二维方式思考一下如何将我们的设计转化为动画。

如果你刚接触Motion,一个简单的方法就是创建故事版。

 

 

故事板在20世纪30年代被华特迪士尼公司(Walt Disney Productions)推广,通过将故事记录为一个个序列的方式帮助动画师和导演进行沟通交流。在交互设计中,故事板可以帮助我们确定一下几点:

  • 需要什么元素;
  • 需要操控元素的哪些属性;
  • 我们将从哪些关键帧开始(稍后再讨论)。

 

举个例子,让我们尝试如果在Haiku中创建一个跳跃的球的动画。

从这个简单的故事板,我们可以定义:

  • 我们需要2个元素:球和影子。
  • 我们想要改变球的位置,球的大小和阴影的不透明度。
  • 我们需要至少3个关键帧来实现动画的无缝循环。

当创建故事板时,尽量不要钻进小细节里,很多灵感和创意都是发生在动画制作开始和迭代视觉效果的时候。所以动画雏形构建得差不多就可以开始了。

开始使用Haiku

如果不想看下面的gif教程的话,可以查看youtube视频教程

 

使用Sketch

在Haiku中,有两种方法可以使用sketch——你可以导入现有的sketch源文件,也可以从头开始创建新的设计元素。

如果你想要开始一个新的设计项目,最好的方法是在Haiku既有的样板文件中,双击进入后编辑。

你同样可以导入既有的Sketch和SVG文件。

 

Haiku通过查找画板和切片,并将它们十分智能地导入到你的库中作为独立的元素。在画出你的球和阴影之后,将形状转换成切片的最简单方法是在sketch中将它们标记为“Make Exportable”。

 

 

点击保存后,你的sketch切片元素将会出现在Haiku的库中:

你可以把元素拖拽进舞台:

在一个属性被编辑的同时,Haiku会自动创建一个关键帧,并在那里定位一个播放头的标记。和我们创建最原始故事板的方法如出一辙,你需要考虑在哪里设置关键帧。

时间轴里的属性可以直接被编辑,或者直接对舞台上的元素进行可视化操作:

现在关键帧 已经设置好了,让我们在时间轴上右击调出内置的补间动画库选定缓动形式,让这个两个关键帧之间产生圆滑的过渡效果。我将使用 Ease In →  Cubic and Ease Out → Cubic,但是我建议初学者可以多尝试不同的补间动画直到找到最适合你的那一个:

使用我们刚刚演示的基本技巧,可以很容易添加更多的细节:在时间轴上添加关键帧,以便在球接近地面时显示阴影;

并将球垂直压扁以模拟真实的物理材质:

 

点击发布自动生成一个唯一的URL用来分享给别人。

 

在Haiku中创建的一切都是纯粹的JS/CSS,随时可以嵌入任何web应用程序,使用Lottie提供原生渲染器更是能够对接iOS和Android项目。

 

看到这里你或许已经想跃跃欲试,创建自己的专属动画,如果你还没有安装Haiku,可以点击这里下载安装

另外你可以在以下社交分享网站中找到持续更新的相关内容:

code实践之如何制作一个简单的全栈原型

受到设计师 Marc Krenn的启发和鼓舞,我开始走出自己的舒服区,拿自己接手的项目开刀实践如何制作一个全栈原型。本文的某些操作和观点部分摘取他的一篇名为Supercharge your Framer prototype with Firebase 的文章,有兴趣的可以去拜读一下他的原帖。

 

 

一、认识全栈原型

1.什么是全栈原型

和我们平时做的普通原型不同的是,全栈原型是通过实时请求数据库去动态填充界面,甚至通过前端触发与数据库进行数据交互去完成某些操作指令。

 

2.全栈原型的应用场景

全栈原型的概念,会帮助我们在设计工作中以下几个方面中有所突破:

  • 全方位还原界面的各种态(初始、常规、边界、报错);
  • 跟踪用户交互行为并采集数据(比如统计用户找到一个按钮并触发所用的时间);
  • 项目资源的复用(比如将品牌色、缓动参数、通用组件保存在云端使得能在多个原型中复用);
  • 远程控制(同理因为多个原型使用同一套数据库,便可以通过操作某个原型修改数据库进而去远程控制另一个原型)

 

二、全栈原型实践

因为编程能力以及篇幅限制,我主要结合自己在搭建后台界面过程中,如何写一个下拉选择器的组件为实例,聊一聊怎样制作一个可以从firebase抓取数据填充内容的动态原型。

1.准备工作

首先对于制作原型的工具选择,Framer是一款为数不多可以编程的设计工具,对于前端工程师上手相当容易,同时对于那些在学习JS编程的设计师,可以用它来验证和提高自己的编程能力。Framer官网的标语就是Design everything,确实,只要是你能想得到的效果,它都能实现。

其次如果想要制作一个动态原型,那首先你需要构思好,那些内容是需要从后端抓取,可以提前以JSON的格式将他们以不同类型组织好,它可以是标量、序列、映射等等不同类型http://www.w3school.com.cn/json/index.asp

所有原型里将会填充的数据在本地先用JSON格式模拟好

 

 

比如我要整理一个平台切换的下拉选项可能会有的内容,我将它分成平台类别和业务线名称,以映射集合的形式写成

client data =
[
{cgy:"APP", name:"appitem01"},
{cgy:"APP", name:"appitem02"},
{cgy:"APP", name:"appitem03"},
{cgy:"WEB", name:"webitem01"},
{cgy:"WEB", name:"webitem02"},
{cgy:"APP", name:"appitem04"},
{cgy:"H5", name:"h5item01"}
]

一级选项有APP,WEB…

二级选项有分别对应的是appitem01,appitem02,appitem03…webitem04…

 

2.界面布局

和静态界面布局不一样的是,页面的结构和内容是由JSON决定的,那么我们只能通过JSON数据,运算获取我们想要布局元素的数量、内容以及其它信息。

接着我们一步一步推导如何在前端编辑JSON进而提取信息去进行页面布局,方法如下:

1)新建clientCgyArry数组,用来存放JSON中所抽取的所有平台类别字段

for i in [0..clientdata.length-1]
#挑出数组字段
clientCgyArry.push(clientdata[i].cgy)

»   [“APP”, “APP”, “APP”, “WEB”, “WEB”, “APP”, “APP”, “APP”, “WEB”, “WEB”]

 

2)显然平台类别数组里重复的字段不可取,需要去重

#为了方便复用,为数组添加一个去重的方法属性
Array.prototype.unique = ->
#新建一个数组存放结果
res = [];
#新建一个空对象
json = {};
#遍历当前数组并从原数组中取出一个元素与对象进行对比
for i in [0..this.length-1]
#如果这个元素不重复,则把它存放到结果数组中,同时把这个元素的内容作为对象的一个属性,并赋值为1
if!json[this[i]] then res.push(this[i]) and json[this[i]]=1;
res;
print clientCgyArry.unique()
» ["APP", "WEB”]

3)接着为了获取每个平台类别下对应的业务线名称,我们可以先定义一个数组将JSON里的键值对按类别分组,具体如下:

for a in [0..clientCgyArry.unique().length-1]
#按去重后的类别新建空数组
clientdataCgy[a] = []
#在平台JSON源里查找
for i in [0..clientdata.length-1]
#如果JSON数据源里有这个平台类别,则把它丢到对应的clientdataCgy子数组里
if clientdata[i].cgy == clientCgyArry.unique()[a] then clientdataCgy[a].push(clientdata[i])
print clientdataCgy
» [
[
{cgy:"APP", name:"appitem01"},
{cgy:"APP", name:"appitem02"},
{cgy:"APP", name:"appitem03"},
{cgy:"APP", name:"appitem04"},
{cgy:"APP", name:"appitem05"},
{cgy:"APP", name:"appitem06”}
]
,
[
{cgy:"WEB", name:"webitem01"},
{cgy:"WEB", name:"webitem02"},
{cgy:"WEB", name:"webitem03"},
{cgy:"WEB", name:"webitem04”}
]
]
#分别在每个子数组里遍历,查找得到业务线字段并打印
for i in [0..clientdataCgy[0].length-1]
print clientdataCgy[0][i].name
» "appitem01"
» "appitem02"
» "appitem03"
» "appitem04"
» "appitem05"
» "appitem06"
for i in [0..clientdataCgy[1].length-1]
print clientdataCgy[0][i].name
» "webitem01"
» "webitem02"
» "webitem03"
» "webitem04"

这样得到这几个关键数组我们就能通过数组里遍历渲染出选择器控件样式:

#渲染下拉选择器样式
#下拉选择器
client = new Layer
parent: sideBar
x: 0
y: logo.y+40
backgroundColor: "transparent"
width: 224
height: 70
z: 0
for c in [0..clientCgyArry.unique().length-1]
#下拉一级选项
client_item = new Layer
parent: list_bg
x: 80
y: 80+32*c
backgroundColor: "rgba(255,255,255,0.9)"
backgroundBlur: 60
width: 158
height: 32
z: 99
name: "client_item"+(c+1)
visible: false
client_item_txt = new TextLayer
parent: client_item
x: 16
y: 8
text: clientCgyArry.unique()[c]
fontSize: 12
fontFamily: "PingFang SC"
width: 158
height: 32
fontWeight: 400
lineHeight: 1.5
textAlign: "left"
color: textColor
#下拉二级选项
for d in [0..clientdataCgy[c].length-1]
secondary_client_item = new Layer
parent: client_item
id: clientdataCgy[c]+d
name: "secondary_client_item"+d
x: client_item.width
y: 32*d
backgroundColor: "rgba(255,255,255,0.9)"
backgroundBlur: 60
width: 158
height: 32
visible: false
secondary_client_item_txt = new TextLayer
parent: secondary_client_item
x: 16
y: 8
text: clientdataCgy[c][d].name
fontSize: 12
fontFamily: "PingFang SC"
fontWeight: 400
lineHeight: 1.5
textAlign: "left"
color: textColor

结构写出来了,那么添加事件就方便了,在一级平台选择悬停时添加事件,展示它下面的业务线选择面板。

#一级选择
for c in [0..clientCgyArry.unique().length-1]
#为一级选择添加鼠标移入移除态
client_item.states =
mouseOver:
backgroundColor:primaryColor01
mouseOut:
backgroundColor:"rgba(255,255,255,0.9)"
#为一级选择添加鼠标移入移除事件
client_item.onMouseOver (event, layer) ->
@stateSwitch("mouseOver")
for i in [0..@children.length-1-1]
@children[i].visible = true
client_item.onMouseOut (event, layer) ->
@stateSwitch("mouseOut")
for i in [0..@children.length-1-1]
@children[i].visible = false

当然一个完整的下拉操作交互应该是 :

点开选择器展示平台类别 » 悬停平台类别选项展示其子业务线 » 选择业务线并且将其字段传给选择器选择框。

具体可以下载我在本地测试的Framer原型查看完整代码演示:https://framer.cloud/ppGVY.

完整的选择器交互效果

为了操作的反馈更明显,我引入了facebook的音效素材包。使得不同的操作有不同的音效提示http://facebook.design/soundkit。

这时候你可以尝试在本地修改clientdata里面的内容,比如多添加一个新的平台类别和对应的业务线{cgy:”H5″,name:”h5item01”},如果界面成功渲染,说明代码运转正常。

 

 

3.搭建数据库

到这里,前面提到的Firebase终于可以压轴出场了,Firebase是一家实时后端数据库创业公司,它能帮助开发者很快的写出Web端和移动端的应用。简而言之就是一家提供BaaS(后端及服务)的公司。当然我们不需要像全栈工程师那样了解它所有的功能,这里主要介绍一下它实时同步JSON数据库的功能。

数据库的搭建流程大致分为一下几个步骤:

1.去Firebase官网https: //firebase.google.com→ 登录 → 控制台 → 创建新项目(国内访问需要翻墙)

2.选择数据库,创建数据表。你可以在firebase上直接添加,也可以载入本地的JSON文件。

3.修改权限,获取访问路径

创建好数据表后,可以观察到生成了一串数据库的网址:通过 这串网址前缀+XXX.json就是这段json文件在firebase上面的访问路径。

比如浏览器里键入https://userbehavior-dashboard.firebaseio.com/clientdata.json就可以访问数据库里的clientdata数据。

由于数据库为避免他人窜改,默认是非公开的,需要秘钥才能访问,这时只要点击Firebase数据界面的规则tab,把读和写的布尔值改为true,就可以让任何人通过网址直接访问(这里仅用于公开原型测试)。

4.在Framer里引入

打开Framer,选择侧边栏里的 snippet » Other » JSON API Call,得到如下代码

Utils.domLoadJSON "https://api.github.com/repos/koenbok/Framer", (error, response) ->
print response.name
print response.url
print response.des cription  

把示例链接替换成你要访问的json链接,response可以自己命名,方便后面引用(注意缩进规则)。比如:

Utils.domLoadJSON "https://userbehavior-dashboard.firebaseio.com/clientdata.json", (error, clientdata) ->
print clientdata
» [
{cgy:"APP", name:"appitem01"},
{cgy:"APP", name:"appitem02"},
{cgy:"APP", name:"appitem03"},
{cgy:"WEB", name:"webitem01"},
{cgy:"WEB", name:"webitem02"},
{cgy:"APP", name:"appitem04"},
{cgy:"H5", name:"h5item01"}
]

打印测试显示数据库访问正常。

到此为止,我们一个动态的组件原型就制作完成了,我们可以把这套下拉选项的内容复用在别的原型里,或者可以通过在firebase上直接操作数据库,去实时同步我们所有复用到数据库的组件原型。

比如在这个原型里,我使用这个组件通过所选择的业务线,判断它的平台类别,进而抓取该平台下的导航数据并将其结构和样式渲染出来。https://framer.cloud/oVmLd (访问需要打开翻墙工具)

5.数据库进阶操作

Firebase和Framer的珠联璧合不仅仅局限在数据的载入上。阅读以下教程,试一试用Marc Krenn写的firebase module去体验其它进阶的数据库操作https://github.com/marckrenn/framer-Firebase#getting-started-in-under-5-minutes 。

三、总结&感悟

全栈原型的制作,让你的设计不仅仅停留在界面,你可能要试着设计信息架构,试着设计数据接口,试着通过代码去还原交互动效…总之,在锻炼编程能力之余,让你能从更广阔的维度去审视你的设计项目,最重要的是对互联网底层运作了解的越深,越能帮助我们在还原设计及创意上有的放矢,利用既有的知识储备去挖掘出更多前所未有的交互体验。

code实践下来,首先我被迫养成了良好的代码标注习惯,由于自己逻辑思维能力较差,加上如果代码修改量过多的话,不做备注隔天就忘记了自己写的什么;其次很高兴自己能坚持下来,因为大部分时间与其说是在写交互,不如说是修复bug,或者说是沉迷于解决一些细节的交互冲突,感谢自己的固执,让我总能找到解决问题的方法,过程虽然痛苦,你若坦荡面对,最终会回报于你的是莫大满足感。

最后,2018年预祝各位工作学习,节节攀高!