Framer 10天交互動(dòng)效特訓(xùn) - 8

Framer 特訓(xùn)8

第四個(gè)案例,加載效果

最終效果

首先我們需要梳理一下加載的過(guò)程,用靜態(tài)界面標(biāo)識(shí)出來(lái),所謂磨刀不誤砍柴工。

靜態(tài)效果

思路整理:

  1. 點(diǎn)擊按鈕
  2. 按鈕變色
  3. 文字放大并縮小
  4. 按鈕變化樣式縮小
  5. 按鈕開(kāi)始加載
  6. 加載完成,按鈕變化樣式還原
  7. 結(jié)束圖標(biāo)出現(xiàn)

思路清楚后,接下來(lái)就是用 Framer 逐一的實(shí)現(xiàn)了。

點(diǎn)擊按鈕

我們先把需要的元素用 Framer 畫(huà)出來(lái),有按鈕,按鈕上的文字,最后出現(xiàn)符號(hào)。把所有動(dòng)畫(huà)寫(xiě)完以后,點(diǎn)擊按鈕觸發(fā)動(dòng)畫(huà)。

# Define variables
width = 240 * 2
height = 48 * 2
green = '#3BE0A5'
grey = '#CECBD4'

# 設(shè)置背景色
Screen.backgroundColor = "#fafafa"

# 設(shè)置默認(rèn)動(dòng)畫(huà)參數(shù)
Framer.Defaults.Animation = 
    curve: Bezier.easeIn
    time: .3

# 畫(huà)按鈕
button = new Layer
    x: Align.center
    y: Align.center
    height: 48 * 2
    width: 240 * 2
    borderColor: green
    borderWidth: 2
    borderRadius: 100
    backgroundColor: null

# 記錄初始 x 值  
buttonOriginX = button.x

# 畫(huà)文字
text = new TextLayer
    parent: button
    text: 'SUBMIT'
    fontSize: 32
    fontFamily: 'Roboto'
    color: green
    x: Align.center
    y: Align.center
    originY: 1

# 畫(huà)符號(hào)
symbol = new TextLayer
    parent: button
    text: '?'
    fontSize: 50
    fontFamily: 'Roboto'
    color: '#fff'
    x: Align.center
    y: Align.center 
    opacity: 0

注意:

  1. 這里記錄一下按鈕的初始 x 位置,因?yàn)樽儞Q長(zhǎng)寬是以(0,0)為固定點(diǎn)的。按鈕縮小時(shí),需要同時(shí)移動(dòng) x 坐標(biāo)讓按鈕視覺(jué)上看上出是以 (center, center) 為固定點(diǎn)。

按鈕變色

按鈕變色給用戶(hù)點(diǎn)擊提供反饋,同時(shí)邊框消失。

# 按鈕變色
buttonChangeColor = new Animation button,
    borderWidth: 0
    backgroundColor: green
    options:
        time: .2

文字放大并縮小

按鈕變色的同時(shí)文字放大,提供 Anticipation, 放大后文字再縮小消失。

# 文字放大并縮小
textScaleUp = new Animation text,
    scale: 1.1
    options:
        time: .2
        delay: .1
    
textScaleDown = new Animation text,
    scale: 0
    opacity: 0  
    options:
        time: .2

按鈕變換樣式縮小

按鈕變成原型,背景色消失,邊框變粗且變成灰色。

# 按鈕變換樣式縮小
buttonChangeStyle = new Animation button,
    borderWidth: 8
    borderColor: grey
    backgroundColor: 'rgba(59,224,165,0)'
    width: button.height
    borderRadius: '50%' 
    x: buttonOriginX + (width - button.height) / 2
    option:
        time:.4
        delay: .2

注意:

  1. x: (width - button.height) / 2記錄的是中心偏移的距離,即 x 需要增加的距離

按鈕開(kāi)始加載

這是最復(fù)雜的一步,這也是我喜歡 Framer 的原因。當(dāng)你用 AE 實(shí)現(xiàn)一個(gè)看似很簡(jiǎn)單的功能,開(kāi)發(fā)可能需要很長(zhǎng)的時(shí)間才能實(shí)現(xiàn)。這時(shí)作為設(shè)計(jì)師,你就需要權(quán)衡項(xiàng)目進(jìn)度能否允許復(fù)雜動(dòng)效的開(kāi)發(fā)。

使用了 Svg 的 stroke-dashoffset, stroke-dasharray 來(lái)模擬實(shí)現(xiàn)圓的加載。同時(shí)使用 Utils.modulate() 映射一個(gè)特定的 Bezire 函數(shù)效果。推薦一個(gè)調(diào)節(jié) Bizire 曲線的好網(wǎng)站,cubic-bezire.

# 按鈕開(kāi)始加載
# svg 中即將用到的屬性
radius = (96-8) / 2
border = 8
viewBox = (radius * 2) + border

# buttonBorder 用 svg 繪制
buttonBorder = new Layer
    x: Align.center
    y: Align.center
    width: viewBox  
    height: viewBox
    rotation: -90  
    backgroundColor: null

buttonBorder.pathLength = 2 * Math.PI * radius
buttonBorder.html = "
    <svg viewBox='#{-border/2} #{-border/2} #{viewBox} #{viewBox}'>
        <circle fill='none' 
        stroke='#{green}'
        stroke-width      = '#{border}'
        stroke-dasharray  = '#{buttonBorder.pathLength}'
        stroke-dashoffset = '#{buttonBorder.pathLength}'
        cx = '#{radius}'
        cy = '#{radius}'
        r  = '#{radius}'>
    </svg>"
buttonBorder.path = document.querySelector('svg circle')

# buttonBorder 的運(yùn)動(dòng)  
proxy = new Layer
    x: 1
    visible: false  
        
proxy.on 'change:x', ->
    offset = Utils.modulate(@.x, [0, 200], [buttonBorder.pathLength, 0])
    buttonBorder.path.setAttribute 'stroke-dashoffset', offset
    
buttonBorderAnimation = new Animation proxy,
    x: 200
    options:
        time: 1.5
        # 自定義 Bezire 函數(shù)
        curve: Bezier(.9,.1,.83,.67)

注意:

  1. 實(shí)際做的時(shí)候,我花了很長(zhǎng)事件把兩個(gè)圓環(huán)對(duì)齊,一開(kāi)始不理解為什么對(duì)不齊。后來(lái)發(fā)現(xiàn),F(xiàn)ramer 在添加 border 時(shí),border 是包含在總 width 內(nèi)的,即 border 寬度不影響該元素的總寬度。但是 svg 矢量畫(huà)圓的時(shí)候,是以 border 的中點(diǎn)開(kāi)始畫(huà)的。所以相比原圖層,會(huì)偏移 border / 2 的寬度。所以 Svg 圖像的原點(diǎn)需要偏移 (- borderWidth/2, borderWidth/2)進(jìn)行對(duì)齊。

加載完成,按鈕變化樣式還原

按鈕邊框消失,寬度和圓角還原,背景色出現(xiàn)。

# 加載完成,按鈕變化樣式還原
buttonChangeBig = new Animation button,
    borderWidth: 0
    width: width
    x: buttonOriginX
    borderRadius: 100
    backgroundColor: green
    options:
        delay: .1
        time: .3
        curve: Bezier.easeInOut

注意:

  1. 同理,x 坐標(biāo)還原到初始狀態(tài)

結(jié)束圖標(biāo)出現(xiàn)

結(jié)束圖標(biāo)出現(xiàn),opacity 和 scale 從 0 到 1,同時(shí)加一個(gè) Spring 曲線增加趣味性。

# 結(jié)束圖標(biāo)出現(xiàn)    
symbolAppear = new Animation symbol,
    opacity: 1
    scale: 1
    options:
        delay: .1
        time: .2
        curve: Spring(damping: .6)

動(dòng)畫(huà)執(zhí)行

將之前的動(dòng)畫(huà)思路,用代碼按順序執(zhí)行。

# 點(diǎn)擊按鈕事件,動(dòng)畫(huà)開(kāi)始
button.on Events.Click, ->
    # 背景色變化
    buttonChangeColor.start()
    # 文字變顏色,并放大
    text.color = '#fff'
    textScaleUp.start()
    # 文字放大結(jié)束后,文字變小,按鈕縮小 
    textScaleUp.on Events.AnimationEnd, -> 
        textScaleDown.start()
        buttonChangeStyle.start()
    # 按鈕縮小結(jié)束后,邊框開(kāi)始加載
    buttonChangeStyle.on Events.AnimationEnd, ->
        buttonBorderAnimation.start()
    # 邊框加載結(jié)束后,按鈕開(kāi)始變大
    buttonBorderAnimation.on Events.AnimationEnd, ->
        buttonBorder.destroy()
        buttonChangeBig.start()
    # 按鈕變大結(jié)束后,符號(hào)出現(xiàn)      
    buttonChangeBig.on Events.AnimationEnd, ->
        symbolAppear.start()

這是一個(gè)不斷調(diào)試的過(guò)程,每一個(gè)動(dòng)畫(huà)的 time, delay, curve 三個(gè)參數(shù)都需要反復(fù)調(diào)整直到產(chǎn)生一個(gè)滿意的視覺(jué)效果。我會(huì)先憑經(jīng)驗(yàn)輸入一個(gè)大概的值,在根據(jù)實(shí)際情況進(jìn)行微調(diào)。你可以調(diào)的時(shí)候畫(huà)一個(gè) timeline 作為草稿。

Timeline

小結(jié)

四個(gè)案例后,筆者對(duì)一般的效果已經(jīng)有了一定了解。但是深感自己在 Web Animation 底層知識(shí)上的薄弱。比如:動(dòng)畫(huà)創(chuàng)意,動(dòng)效節(jié)奏,Svg, Canvas 的 JS 實(shí)現(xiàn)。所以筆者接下來(lái)會(huì)多了解 Web Animation 方面的理論知識(shí),為做更好的動(dòng)效打下基礎(chǔ)。我們下期見(jiàn)。

Reference

Framer 線上演示:https://framer.cloud/jvcnt

完整代碼


# Coded by Joey in April, 2017

# 導(dǎo)入 Roboto 字體
Utils.insertCSS("@import 'https://fonts.googleapis.com/css?family=Roboto:300,400,700';")

# Define variables
width = 240 * 2
height = 48 * 2
green = '#3BE0A5'
grey = '#CECBD4'

# 設(shè)置背景色
Screen.backgroundColor = "#fafafa"

# 設(shè)置默認(rèn)動(dòng)畫(huà)參數(shù)
Framer.Defaults.Animation = 
    curve: Bezier.easeIn
    time: .3

# 畫(huà)按鈕
button = new Layer
    x: Align.center
    y: Align.center
    height: 48 * 2
    width: 240 * 2
    borderColor: green
    borderWidth: 2
    borderRadius: 100
    backgroundColor: null

# 記錄初始 x 值  
buttonOriginX = button.x

# 畫(huà)文字
text = new TextLayer
    parent: button
    text: 'SUBMIT'
    fontSize: 32
    fontFamily: 'Roboto'
    color: green
    x: Align.center
    y: Align.center
    originY: 1

# 畫(huà)符號(hào)
symbol = new TextLayer
    parent: button
    text: '?'
    fontSize: 50
    fontFamily: 'Roboto'
    color: '#fff'
    x: Align.center
    y: Align.center 
    opacity: 0
    scale: 0

# 按鈕變色
buttonChangeColor = new Animation button,
    borderWidth: 0
    backgroundColor: green
    options:
        time: .2
    
# 文字放大并縮小
textScaleUp = new Animation text,
    scale: 1.1
    options:
        time: .2
        delay: .1
    
textScaleDown = new Animation text,
    scale: 0
    opacity: 0  
    options:
        time: .2

# 按鈕變換樣式縮小
buttonChangeStyle = new Animation button,
    borderWidth: 8
    borderColor: grey
    backgroundColor: 'rgba(59,224,165,0)'
    width: button.height
    borderRadius: '50%' 
    x: buttonOriginX + (width - button.height) / 2
    option:
        time:.4
        delay: .2

# 按鈕開(kāi)始加載
# svg 中即將用到的屬性
radius = (96-8) / 2
border = 8
viewBox = (radius * 2) + border

# buttonBorder 用 svg 繪制
buttonBorder = new Layer
    x: Align.center
    y: Align.center
    width: viewBox  
    height: viewBox
    rotation: -90  
    backgroundColor: null

buttonBorder.pathLength = 2 * Math.PI * radius
buttonBorder.html = "
    <svg viewBox='#{-border/2} #{-border/2} #{viewBox} #{viewBox}'>
        <circle fill='none' 
        stroke='#{green}'
        stroke-width      = '#{border}'
        stroke-dasharray  = '#{buttonBorder.pathLength}'
        stroke-dashoffset = '#{buttonBorder.pathLength}'
        cx = '#{radius}'
        cy = '#{radius}'
        r  = '#{radius}'>
    </svg>"
buttonBorder.path = document.querySelector('svg circle')

# buttonBorder 的運(yùn)動(dòng)  
proxy = new Layer
    x: 1
    visible: false  
        
proxy.on 'change:x', ->
    offset = Utils.modulate(@.x, [0, 200], [buttonBorder.pathLength, 0])
    buttonBorder.path.setAttribute 'stroke-dashoffset', offset
    
buttonBorderAnimation = new Animation proxy,
    x: 200
    options:
        time: 1.5
        # 自定義 Bezire 函數(shù)
        curve: Bezier(.9,.1,.83,.67)
    
# 加載完成,按鈕變化樣式還原
buttonChangeBig = new Animation button,
    borderWidth: 0
    width: width
    x: buttonOriginX
    borderRadius: 100
    backgroundColor: green
    options:
        delay: .1
        time: .3
        curve: Bezier.easeInOut

# 結(jié)束圖標(biāo)出現(xiàn)    
symbolAppear = new Animation symbol,
    opacity: 1
    scale: 1
    options:
        delay: .1
        time: .2
        curve: Spring(damping: .6)

# 點(diǎn)擊按鈕事件,動(dòng)畫(huà)開(kāi)始
button.on Events.Click, ->
    # 背景色變化
    buttonChangeColor.start()
    # 文字變顏色,并放大
    text.color = '#fff'
    textScaleUp.start()
    # 文字放大結(jié)束后,文字變小,按鈕縮小 
    textScaleUp.on Events.AnimationEnd, -> 
        textScaleDown.start()
        buttonChangeStyle.start()
    # 按鈕縮小結(jié)束后,邊框開(kāi)始加載
    buttonChangeStyle.on Events.AnimationEnd, ->
        buttonBorderAnimation.start()
    # 邊框加載結(jié)束后,按鈕開(kāi)始變大
    buttonBorderAnimation.on Events.AnimationEnd, ->
        buttonBorder.destroy()
        buttonChangeBig.start()
    # 按鈕變大結(jié)束后,符號(hào)出現(xiàn)      
    buttonChangeBig.on Events.AnimationEnd, ->
        symbolAppear.start()            
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,232評(píng)論 4 61
  • 21. How much? 多少錢(qián)? 22. I'm full. 我飽了。 23. I'm home. 我回來(lái)了。...
    糖月陽(yáng)閱讀 216評(píng)論 0 0
  • 在殘缺的生活里,接受了缺陷,便是完美,隨緣便活的自在。不接受缺陷,便是立志,也是好事。如此,無(wú)論是否活在當(dāng)下,都是...
    關(guān)中人閱讀 570評(píng)論 0 0
  • 不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心不開(kāi)心...
    這個(gè)瓜甜閱讀 186評(píng)論 0 0
  • 性別:女。 出發(fā)地點(diǎn):北京。 隨行人數(shù):0。 天數(shù):6天。 耗資:住250+吃400左右+行420+帶回家...
    MUMA嚶嚶嚶閱讀 798評(píng)論 6 3