恭喜你成为UI中国推荐设计师 (详情)
//百度统计 20220402 uicn

您的意见是我们 UI 中国进步的动力!
点击立即反馈按钮,发表您的意见!
立即反馈
QQ群反馈
您也可以加入UI中国官方反馈群进行反馈!
群号:302892100
备注:反馈问题后@管理员能让我们及时了解您的意见

提交需求

赛事与广告咨询合作,请填写需求表单,我们会在第一时间与您联系!

0/20
0/200

设计大赛

  • 设计大赛
  • 发布广告
  • 发布招聘
  • 其它需求

提交完成
感谢您对UI中国的支持和信赖!
QC教程:横轴滚动效果
0.0°
2014-07-18 自译外文 教程 原作者: Dawid Woldu 举报 45211 116 30 8

本文将是半原创,除了将会根据作者提供的思路,制作出效果

其中包含的大段比例问题和表达式思想需要各位在实践中学习,光看文字可能无法理解。

原文地址:

http://macoscope.com/blog/quartz-composer-origami-mouse-headaches/

http://macoscope.com/blog/science-behind-snapping-scroll-part-i-dragging/

http://macoscope.com/blog/the-science-behind-snapping-scroll-part-ii-animation-logic/#more

一、Quartz Composer.与Origami,令人头疼的Mouse模块——制作出独立于QC视窗的、手机屏幕内坐标系统,提供更精确的鼠标指针位置数据

补充:请注意,当Origami发布1.2版本后,Facebook重制了Phone Patch,现在支持了横屏模式。本文的部分内容可能会失效(但是竖屏模式依然有效,大多数情况下,设备和视图的高度比率依然为1.6左右,而现在设备尺寸守视图窗口宽度影响)


自从Facebook 发布了Origami,再加上jQC,Avacado等强力插件,Quartz Composer变得前所未有的易用,很多UI/UX设计师,包括我,都从其中受益。

然而,QC原生的交互模块(interaction patch0和Origami的Phone模块在结合使用时,还是有一点小问题的。首当其冲的就是,如何将“以QC为衡量尺度所测量的鼠标绝对位置”转化为”Origami所提供的手机模板屏幕中的相对位置“

这一点为何重要?因为Origami可以非常的方便设计师打造出细腻的交互效果,快速产生原型。但是交互设计师都知道,完整的交互流程必然是”操作->判定->反馈“。如何精确的测量“操作事件”,亦非常重要。如果所支持的操作事件越多,那么所达成的效果也越精细。因此,如果能精确的测量出鼠标指针(或者在移动端实际应用中的触控点位置),那么便能构建出更精确、更有理有据的交互效果。
这里编者举个例子吧。

在面向用户时,Paper的卡片隐喻合理且直观,交互效果异常华丽,往往能在合理中带给用户意想不到的惊喜。设计者在设计时,肯定是付出了很多很多心思。

例如上图卡片底部1/3处点击和卡片2/3处点击的效果完全不同,1/3处点击卡片,上弹的速度极快;而2/3处点击,上弹的速度会稍慢一些。

再比如上方图片区域(图中的红色方块),既支持点击调用出新卡片(自下而上滑出),又支持左右滑动切换话题。

这都需要交互设计师在设计时,精确定义不同的操作事件,进而提供不同的交互效果。


问题所在

QC默认的坐标系统,是按照整个视图窗口而设定的。它的坐标有着自己的单位数值,原点是(0,0),而X坐标轴的数值 -1和1分别代表视图窗口的左右边缘。

不管视图窗口宽度如何,当X轴坐标都代表着屏幕窗口的左右边缘。

而在此屏幕宽度下,Y Postion设置为0.7代表上边缘。

改变窗口宽度,圆球X postion为1时,始终处于屏幕右边缘

改变窗口宽度,圆球Y postion为0.7时,小球开始上下移动

问题出来了,X轴位置是相对不变的,而Y轴位置却改变。

如下图,在不同的屏幕宽度下,Y轴的位置取决于视图窗口的高宽比。

CQ coordinates

而当前Origami的Phone Patch,根据上面所提到的QC坐标机制,为了让屏幕中的视觉元素可见,手机在竖屏情况下的缩放主要取决于视图窗口的高度而不是宽度。

虽然手机屏幕的中心原点和视图窗口的中心原点契合了,但是手机屏幕中元素的位置关系,依然是参照QC视图窗口的坐标体系而定。


下图为视图窗口在不同高宽比下,位置点的变化

绿色:理想状况

红色:实际情况

解决方案

显而易见,精确的交互效果以精确的操作判定为基础,因此我们想要改良这一点。我们希望能够改良坐标系统,位置点(1,1)处于手机屏幕的右上角。


首先建议的是将Mouse套在Render In Image 中。Render in Image的Pixels Wide和Pixels High参数(一般和Phone Dimensions Patch相连)会迫使Mouse Patch的输出按给定高宽比输出。


snapping_scroll_Illu4

这意味着现在,X Postion的1,依然代表着视图窗口的右边缘。

但是上边缘和下边缘需要用1和-1乘以Render In Image的高宽比,而不是乘以视图窗口。

例如,对于iPhone来说,视图窗口的顶部和底部变为1.775和-1.775,因为1136/640=1.775

Mouse这个模块,输出的结果也是按照QC的长度单位,而不是像素,因此要使用Units to Pixels模块转化一下。我们想要的坐标结果是左右上下分别是320,-320,568和-568。

既然设备尺寸是和视图窗口的高度有关的,那么可以让Mouse的输出乘以这个比率。

那么设备的尺寸比例和视图窗口高度又怎样的比例关系呢?可以通过测量得知,也可以自己打开Origami的Phone.qtz研究,我研究出来了,比例大概是1.6倍。视图窗口比手机屏幕高大约1.6倍。

因此,只需要Y Postion乘以1.6,就可以了。Y Postion的1.775或者568代表顶部,-1.775/-568px代表底部。

OK,那么X轴怎么办呢。我们需要取消连接鼠标X轴位置和视图窗口宽度的关系。为了达到这个目的,我们需要找到视图窗口的高宽比。这里用了Rendering Destination Dimensions来实现这个目标。


snapping_scroll_illu3

不能将Rendering Destination Dimensions放在Render in Image里面,我们需要在Render in Image里面Publish input一下,然后将Rendering Destination Dimensions和Render in Image连接起来。


现在,我们知道了视图窗口的高宽比,手机的高宽比,以及二者之间恒定的比例。只需要将Mouse的X Position乘以窗口的高宽比,然后除 “手机高宽比除以1.6”

这样,我们就可以侦测到鼠标指针在手机屏幕内的位置,以便提供更精确的数据进行判定,提供更精准的交互效果。

二、Snapping Scroll背后的技术原理 – 第一部分:拖动效果


在我的上一部分中,我讲述了QC基本的坐标系统,解释了如何将Mouse Patch的输出转化为符合Origami插件中手机屏幕尺寸的输出结果。

在开始教程之前,我先贴上Snapping Scroll的源文件。现在我们来讲讲这个效果背后的技术原理。

根据上一篇文章的知识,已经制作了相对坐标系统的源文件,

下载地址:SnappingScroll 

步骤 1

第一步我们首先要把ViewerToScreen X输出到Layer的X Postion上

正如我们预计的那样,图层的X轴位置会根据鼠标指针的X轴位置改变而改变。注意是图层的中心店跟随着鼠标(因为该图层的锚点设置为中心——Anchor Point- Center)

为了让效果更佳有趣,这里小小改制了一下,更换了一下图像。。。。


OK,下一步是当鼠标按压时,呈现这个效果。

步骤 2

这里要使用Sample & Hold这个Patch。这个Patch的工作原理非常简单,在采样(Sample)时,采样参数为1,输出即为输入。当不采样时,采样参数为0,输出值为最后采样的输入值。

这就是我们想要的效果——当我们按压鼠标按键的时候,图层会开始跟随鼠标指针移动。而当我们松开鼠标按键的时候,图层会停下来。

创建一个Sample & Hold 模块,命名为SampleOnDrag。

建立Interaction 2,将Drag连接到Sampling上,此为判定是否触发采样

然后,将ViewerToScreen矫正后的Mouse X Postion(其实就是ViewerToScreen输出的Screen X)连接到输入值Value上。

最后将输出值Value连接到图层的X Position上。


效果还不错,但问题在于,每次我们松开鼠标后,移动一点指针,再次点击,图层的中心点会瞬间移动到鼠标指针的位置,而且看起来还有点“卡顿”

我们只希望在按压的时候,图层会根据指针的移动方向而移动——也就是在按压时,图层在X轴位移量=鼠标在X轴位移量。而不是在按压的时候,图层中心点先跳到鼠标指针的位置再位移。

我们只想取样鼠标的运动方向和运动位移这两个因素,具体坐标位置,我们并不想要。而且,表达式可以帮助我们获取方向信息,因此我们想要采样的其实只有位移量。

步骤 3

在我们的这个案例中,位移量的公式应该是:

新图层的位置=鼠标指针当前位置-鼠标指针按压时的位置
因此,我们需要知道我们在什么位置开始按压鼠标的。为了获取这一信息,我们需要再建立一个Sample & Hold模块(命名为SampleOnPress)

我们来分解一下Drag(拖移)这一交互动作,肯定是先需要点击一下(无论是用指针还是手指),然后开始移动。

也就是说一瞬间点击鼠标时,这时用Pulse->SampleOnPress来取样点击鼠标时的鼠标位置

而SampleOnDrag是移动的位移量。

SnappingScroll  tutorial. Step 3. Composer screenshot

因此,将Interaction 2的Drag再接出来一个到Pulse(将持续信号转换为单个脉冲信号)的Input Signal上。

现在有了拖移开始点的位置信息

然后,用开始点的位置减去结束点的位置,所获得的绝对值,就是我们在按压鼠标开始拖动后,想让图层得到的位移量。


创建Mathematical Expression模块,命名为(Distance),打开检查器(cmd+2),设置里面输入我们的公式

currentMousePosition - mousePositionOnPress

输入完成后,自动创建2个输入点。ViewrToscreen的 Screen X接到currentMousePosition上,

而SampleOnpress的输出接到mousePositionOnPress上。

最后,整个表达式的输出接到SampleOnDrag的Value上。

最后的效果,图层的位移量只等于鼠标的位移量,而不会出现,在屏幕上点击指针时,图层的中心点会立即移动到鼠标指针的X轴位置。

step_3_snappingScroll

然而,我们发现,每次移动时,图层都是从X=0的点开始运动。这是因为当我们每次按压鼠标的时候,currentMousePosition(当前鼠标位置)和mousePositionOnPress(按压时鼠标位置)是相同的。相减得0,而图层的锚点是中心,因此会出现上述结果。

步骤 4

现在需要另外一个数值量的信息——开始移动前,图层的X轴位置信息。

那么运动结束后图层的X轴位置=图层移动前X轴位置+鼠标指针X轴位移量

公式应该是

New Object Position (新图层位置)= Old Object Position(旧图层位置) + Current Mouse Position (当前鼠标指针位置)– Mouse Position onPress(按压时鼠标指针位置)

那么我们来修改一下表达式Mathematical Expression模块

oldLayerPosition + currentMousePosition - mousePositionOnPress

那么怎么获取运动前图层位置信息呢,只需要再简历一个Sample&Hold模块(命名为SampleOnRelease)

输入值接的是SampleOnDrag的输出,输出值接到修改后表达式的oldLayerPosition上。而Sampling——采样的判定条件,我们接入Interaction 2的Click(点击,因为拖移=点击+移动)


最后看看效果吧。

休息一下,我们下面进入第二部分,打造一些运动效,并限制图层的开始和结束位置

补充

  1. 发文此文后,我注意到Click在鼠标松开按键时,依然采样。因此建议新建一个Pulse,Interaction2的Drag作为输入,Cmd+2进行设置,Detection Mode设置为Trailing Edge。

三、Snapping Scroll背后的技术原理——第二部分:动效和逻辑


单向动效

我们来看看Classic Animation这个模块。这个模块工作原理很简单,它里面预设了多种运动曲线,用户可以设置运动时间,运动会根据设置的运动曲线和运动时间而定。一般用在一些反复性的动效上(例如,侧拉菜单的打开/关闭),结合Switch模块的1/0切换可以创造打开/关闭效果。

但是,这跟我们的这个效果可能无关,我们的开始和结束量是不确定的、动态的。而Classic Anmation的一般用法是接Transition用固定点移动到另外一个固定点,这个量的变化是“绝对”的。

Classic Animation的变化特性是,当变到Transition的End Value时,会保持该数值不变,除非再次操作触发。(我觉得可以试试把Duration持续时间设置为0,重设数值。然后再将Duration重设置为原来的数值。用语言解释起来很复杂,详情看提供的源文件吧)


这里需要使用数学表达式模块Mathematical Expression,公式为:

on_off ? progress : -progress+1

当开关处于打开ON的状态(逻辑值为1),我们按原来的进程(Progress)走。当开关处于关闭OFF状态(逻辑值为0),我们将使用负的进程量(-progress)+1作为输出。这样,动效是否开启的逻辑值一直从0到1,无论开关Switch的输入值是0还是1

这一大段可能很难理解,而且上面也提到过使用Click作为触发,可能会导致的一系列问题,这里我提供了到这一步的源文件,而且我创建了Marco Patch,将模块整理的清晰有序。

下载地址: SnappingScroll_tutorial_step_4_corrected

步骤 5

上述4个步骤完成了鼠标拖动时,图层随之移动的效果。

这一步开始,我们想要创造当我们松开鼠标时,图层回弹到确切位置的效果。为了实现这种效果,我们构建了Classic Animation模块和Switch模块的标准组合,以便触发动效。同时还利用了数学表达式(步骤4提到的原理)来确保动效一直从0到1。这样无论图层X轴的开始值和结束值是多少,都能触发返回确定位置的动效。按下图连接。

(编者注,总而言之,就是拖动时,图层可以随意移动,位移量=鼠标位移量,但是松手后,会触发动效,返回到2个指定位置)

Animation_Setup

下一步,我们创建一个Multiplexer模块,让我们可以在鼠标按键松手后,让图层在X轴的2个位置切换。

将Interaction 2的Drag输入到Source Index,

SampleOnDrag输出到Source #1

Transition的输出到Source #0

最后Multiplexer输出到图层的X Postion

编者注:这个Jason图层就是我们指的那个可拖动图层

Transition的起始值Start Value,用的是SampleOnDrag的输出值,也就是释放按键后的图层位置。

Transition的结束值,我们暂时用0(后面会补充2个状态)

现在我们不需要SampleOnRelease这个模块了,因为我们按键松手后,图层会按动效回到指定位置。删掉SampleOnRelease模块,Transition输出到Distance数学表达式模块的oldLayerPosition上。

然后,我们想要让松手时开始动效,返回位置,因此OnRelease输出到Switch的Flip上。

 (注意Sample OnDrag接到Multiplexer的Source #1上,Transition的Value接到Source #0上,别顺序错了)

Tutorial Step 5

快完成了,但是现在结束值只有一个0,因此无论怎么拖动,松手后,图层都会返回到原点位置。下一步我们将改变这一现象。

步骤 6


在这一步中,我们将构建2个位置,让鼠标按键松手后,根据情况返回到这2个位置。我们暂且管他们叫做Low Edge和High Edge吧。

我们图层动效,开始量由SampleOnDrag这Patch决定,采样的是鼠标松手后图层的X轴位置。

而结束量上面也说了,将有2个位置。

共有2个位置点,Low和High,我们需要检测以下图层是否超越了其中一个的临界值,如果超越了其中一个的临界值,那么结束值将切换到另一个入口点的X轴位置。

因此,我们创建一个数学表达式Mathematical Expression模块,我们管它叫做Threshold Detector(临界探测器). 打开设置面板,输入以下公式:

currentEdge == lowEdge && currentPosition > lowEdge + threshold || currentEdge == highEdge && currentPosition < highEdge - threshold


尽管这个公式还可以缩短,但是目前这个公式是最容易理解的。

currentEdge指的是Low和High2个返回位置点中得一个。而currentPosition当前位置,我们可以从SampleOnDrag中获取,我们可以手动设置临界值。

如果满足以下状况的一种,公式的逻辑输出值将变为1:

1) currentEdge等于lowEdge,并且currentPosition大于 lowEdge + threshold(临界值)

或者

2) currentEdge等于highEdge,并且currentPosition小于highEdge-threshold

创建两个输入分离器(input Splitters)命名为lowEdge和HighEdge,右键单击,Publish input

创建Multiplexer模块, 命名为Current Edge,将low/high Edge的输入接到Source #0 和 Source #1上。

创建Switch模块,输出到Multiplexer得Source Index模块。然后Multiplexer的输出接到数学表达式临界探测器的currentEdge上。

创建一个Logic模块,设置为AND模式。数学表达式的输出和PulseOnRelease接到逻辑模块的输入上,输出接到Switch的Flip上。这样就能才鼠标松手后,触发临界探测,自动选择最近的点触发动效。

Threshold_Detector

数学表达式的作用:临界探测器或一直探测,我们在拖动图层时,是否超越了其中一个点的临界值,如果超过,那么将动效运动到另外一个点。

逻辑模块的作用:仅当鼠标按键松手时,才会有效。

Low Edge, High Edge, Threshold的数值,0,360, 100(编者,我的是0,360,100)

OK,这就是效果。。。

步骤 7

最后,可以用Marco Patch整理一下模块,然后Publish相关的input,方便在上一层级修改参数。

到这一步源文件下载地址: Step 7 file

更新:2014-07-18

收藏

116人已收藏

MartinRGB

http://www.MartinRGB.com

  • 234

    作品

  • 1.7w

    粉丝

  • 413

    关注

  • MartinRGB.com
  • Icon Freebie - Code
  • 实验系列II —— Music App For Tv/Pad
  • Private Trainer 引导页实现
相关标签

    猜你喜欢

      2014-07-18 自译外文 教程 原作者: Dawid Woldu 举报 45211 116 30 8

      QC教程:横轴滚动效果

      0.0°

      你确定要举报QC教程:横轴滚动效果

      如果查出恶意举报,十天内禁止提交任何举报申请。

      0/200

      上传证据: 超过10M的附件请使用网盘地址

      点击上传附件

      对谁可见:

      全部设计师
      • 全部设计师
      • 推荐设计师和认证设计师

      您确认要推荐?

      该作品发布时间:2014年07月17日

      评分

      完整度

      启发性

      勤奋性

      排版布局

      推荐心得

      建议20-200字以内

      0/200

      30
      116
      8

      账号或密码错误,请重新输入

      账号或密码错误,请重新输入

      登录

      手机号

      发送验证码 120s 验证码错误

      登录
      第三方账号登录