iOS炫酷動畫(二)

O(∩_∩)O哈!又是一個很cool的動畫。原作者在這里。畫面看著太美好,于是又試著用Swift寫了一個。我的在這里

1.gif
動畫分解

1、首先是橢圓背景色的漸變,灰色---》淡藍色。

2、臉的動畫。這里又分為臉盤(??就這么叫吧)和器官(2眼睛+1嘴巴)的動畫。

  • 臉盤的動畫,比較簡單,就是x的位移。
  • 眼睛+嘴巴這個整體的動畫,有個回彈的效果。先是向右飛出去,然后到達右邊之后,又從左邊飛進來,最后回彈一下。

3、嘴巴的動畫。off的時候,是個長方形的嘴,切換到on,變成了笑臉嘴,并且有個逐漸張開的過程。

AIYA,還真是難描述。

元素分解

知道了動畫步驟之后,元素就比較好分了。臉盤是1個layer,2眼睛+嘴巴==1個layer,橢圓背景=1view。

開工開工
嘴巴

首先注意到的是嘴巴的繪制,on和off的狀態(tài)其實是2種不同的曲線,長方形很好畫,那么張開的嘴呢?當然都是用萬能的貝塞爾曲線啦。其實看了代碼,都覺得簡單o(>﹏<)o。

閉嘴的frame=(0.25w, 0.7h, 0.5w, 0.1h)
張嘴的,x,y,w都是一樣的,只不過是控制2個control point的位置。

private func mouthPath() -> UIBezierPath {
        
        if isOn {
            let path = UIBezierPath()

            path.moveToPoint(CGPointMake(mouthRect().origin.x, mouthRect().origin.y))
            path.addCurveToPoint(CGPointMake(mouthLenth() + mouthRect().origin.x, mouthY()), controlPoint1: CGPointMake(mouthRect().origin.x + mouthOffset / 4, mouthY() + mouthOffset / 2),
                                 controlPoint2: CGPointMake(mouthRect().origin.x + mouthOffset * 3 / 4, mouthY() + mouthOffset / 2))
            path.closePath()
            
            return path
        } else {
            let path = UIBezierPath(rect: mouthRect())
            return path
        }
    }

眼睛

眼睛就是2個橢圓,有現(xiàn)成的。frame=(0.2w, 0.25h, 0.4w, 0.6h)

private func rightEyePath() -> UIBezierPath {
        let origin = rightEyeOrigin()
        let size = eyeSize()
        let path = UIBezierPath(ovalInRect: CGRectMake(origin.x, origin.y, size.width, size.height))
        
        return path
    }
眼睛+嘴巴

其實就是在layer上面,分別把他們畫上去。

override func drawInContext(ctx: CGContext) {
        
        let bezierLeft = leftEyePath()
        let bezierRight = rightEyePath()
        let bezierMouth = mouthPath()
        
        CGContextAddPath(ctx, bezierLeft.CGPath)
        CGContextAddPath(ctx, bezierRight.CGPath)
        CGContextAddPath(ctx, bezierMouth.CGPath)
        CGContextSetFillColorWithColor(ctx, color().CGColor)
        CGContextSetStrokeColorWithColor(ctx, UIColor.clearColor().CGColor)
        CGContextFillPath(ctx)
    }

臉盤/橢圓背景

這個更簡單了,用cornerRadius或者bezierPath都行。

嘴張開的動畫

因為嘴是用bezier曲線畫的,有2個control point。所以主要是操控control point,來實現(xiàn)張開的效果。

為了支持自定義屬性動畫,需要用到needsDisplayForKey,改變屬性后,可以引發(fā)drawInContext重繪。mouthOffset最后其實是等于mounLength的,所以只需要將mouthOffset從0變到mounLength即可。

internal override class func needsDisplayForKey(key: String) -> Bool {
        if key == "mouthOffset" {
            return true
        }
        
        return super.needsDisplayForKey(key)
    }
    
動畫順序

拿從off到on的過程來說。
1、背景漸變+臉盤移動+器官向右飛出
2、臉盤移動的動畫結(jié)束后,器官從左往右飛出,并回彈。同時嘴巴開始張開動畫。
3、回彈動畫結(jié)束,整個動畫結(jié)束。

動畫注意

在動畫結(jié)束之后,要將對應(yīng)值設(shè)成動畫之后的值。

override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
        if flag {
            if let type = anim.valueForKey("animation") as? String {
                // 臉盤移動到端點
                if type == "faceBgLayerAnimation" {
                    
                    faceBgLayer.removeAllAnimations()
                    faceBgLayer.position = positionOfFaceView(!isOn)
                    
                    faceLayer.isOn = !isOn
                    faceLayer.mouthOffset = !isOn ? faceLayer.bounds.size.width / 2 : 0
                    faceLayer.setNeedsDisplay()
                
                    if (!isOn) {
                        mouthAnimation(isOn, offset: faceLayer.bounds.size.width / 2)
                        moveRightBackAnimation()
                    } else {
                        moveLeftBackAnimation()
                    }
                } else if type == "backgroundAnimation" {
                    
                    self.backgroundColor = isOn ? onColor : offColor
                    
                } else if type == "moveBackAnimation" {
                    
                    faceLayer.removeAllAnimations()

                    isOn = !isOn
                    isAnimating = false
                }
            }
        }
    }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復(fù)雜,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,690評論 6 30
  • 轉(zhuǎn)載:http://www.itdecent.cn/p/32fcadd12108 每個UIView有一個伙伴稱為l...
    F麥子閱讀 6,569評論 0 13
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,001評論 25 709
  • 每個UIView有一個伙伴稱為layer,一個CALayer。UIView實際上并沒有把自己畫到屏幕上;它繪制本身...
    shenzhenboy閱讀 3,253評論 0 17
  • 我忍不住想睡了 它卻一直阻攔我 打開我的眼 卻什么都看不見 也不知道 張開眼看見的 和睡了 有何區(qū)別
    滿島遙閱讀 164評論 0 0

友情鏈接更多精彩內(nèi)容