[Framer] 添加 SVG 图层,让工程师追着打的效果成为现实

Framer 框架给出的基础动效多数情况下是足够用的,但总归未免太过乏味,你一定希望有更「炫」的效果来支撑你的设计脑洞。这篇文章帮助你在自己的 Framer 原型中添加 SVG 图层,实现更多意想不到的视觉效果。并且理直气壮的和工程师同学说「我都写出来了,你也写出来吧!」

一、让图层支持 SVG

layer.classList.add("svgBox")

从加上这行开始,目标图层就已经支持 SVG 了,因为 Web 本身支持 SVG,所以我们并不需要加载其他的辅助模块,只要让我们的图层添加相关的类就可以了。

当然,这时候,我们的 Preview 区域不会有任何的反应,因为我们只是让图层支持 SVG 的显示,但是没有规定任何 SVG 图形。

二、 SVG 容器和图形

layer.html = """
    <svg viewBox = '0 0 750 750' version = "1.1">
    </svg>
"""

上面这段代码,建立了一个位置在图层左上角,宽度高度都是 750 的 SVG 图形的容器。我们可以看到,声明 SVG 容器的描述内容被我们放在了 layer.html 中,通常情况下给 Framer 中的对象添加 html 的内容都会通过这种方式。

这时,我们就可以在容器中任意添加自己需要的元素,例如:

layer.html = """
    <svg viewBox = '0 0 750 750' version = "1.1">
        <rect x="0" y="0" width="250" height="250" fill = "blue" />
        <circle cx="300" cy="400" r="40" fill="red"/>
    </svg>
"""

这时,我们的 Preview 区域将会看到一个矩形和一个圆形,如下图:

至此,大家应该已经了解了 SVG 图形在 Framer 中使用的相关套路,更多的 SVG 内容描述方法和规范,可以移步这里:SVG 教程

三、 做一个会被工程师追着打的范例

讲过了相关技术基础,可以进入和原型相关的实例环节 —— 通过 SVG 中贝塞尔曲线的特性,制作一个「粘糊糊」的 OverDrag 区域。

首先,先快速的建立一个可以 OverDrag 的典型 TableView。观察图层列表,你一定发现了,我预留了一个叫 dragEffect 的图层用作显示 SVG 图形,同时有个叫 xAnimation 的迷图层被设置成了 Visiable = false,之后我们会把它作为一个 Trick 用到。

接下来,我们将会在 SVG 容器中构造一条路径,应用了 id 为 grad1 的渐变填充,并且对他的 id 进行了定义——"curve"。因为在没有 OverDrag 时,应该为初始状态,所以他的控制点位置为 (375, 0) ,也就是屏幕的顶端中央,因此目前我们并不能看到效果——它还是一条直线。

dragEffect.html = """
    <svg viewBox='0 0 750 750' version = "1.1">
        <linearGradient id="grad1" x1="0%" y1="0%" x2="0%" y2="100%">
            <stop offset="0%" style="stop-color:rgb(255,255,255);stop-opacity:1" />
            <stop offset="100%" style="stop-color:rgb(255,255,255);stop-opacity:0.4" />
        </linearGradient>
	<path id ="curve" d ="M 0 0 q 375 0 750 0" fill="url(#grad1)"/>
    </svg>
"""

进而,我们希望在 OverDrag 时根据手指和列表的位置对曲线的控制点进行控制。因此,我们对 Drag 事件进行监听。在 Drag 事件发生时,通过 querySelector 查找器根据刚才设置的 id 选中修改相关语句,把控制点的目标 x 值、 y 值同步到 SVG 容器中。

feedList.on Events.Drag, (event) ->
    # 取手指的 x 位置,并设置范围
    xVal = Math.max(Math.min(event.point.x, maxX), minX)
    # 取 TableView 的 y 位置,并设置范围
    yVal = Math.min(feedList.y - 44, maxHeight)
    document.querySelector('.svgBox #curve').setAttribute('d','M 0 0 q '+xVal+' '+yVal+' 750 0')

加入上方代码后,我们在拖拽列表的时候,就已经可以看到拖拽时的理想效果了。不过在松开手后,我们缺少一个合理的过渡。现在我们需要让控制点的 x 位置缓慢居中,y 位置跟随 TableView 回弹。因此加入下方代码:

feedList.on Events.DragEnd, (event) ->
    xAnimation.x = Math.max(Math.min(event.point.x, maxX), minX)
    xAnimation.animate
        x: 375
        options:
            time: 1.5
            curve: Spring(damping: 0.90)

xAnimation.on "change:x", ->
    if feedList.draggable.isAnimating == true
        yValAfter = Math.min(feedList.y - 44, maxHeight)
        xValAfter = xAnimation.x
        document.querySelector('.svgBox #curve').setAttribute('d','M 0 0 q '+xValAfter+' '+yValAfter+' 750 0')

至此,整个效果已经达到了我们的预期,值得注意的是,这里 x 的归位动画所需的值,通过传导一个隐藏图层的普通移动动画来实现,这是一个还算常用的 Trick。

在线预览 & 源码地址:粘粘的 OverDrag

编辑于 2017-04-23