layer高級動畫-擠壓動畫

當(dāng)看到遮罩層類的動畫和碰撞或者擠壓這樣的視圖時,應(yīng)該涉及多個形狀視圖間的動畫通危。此時,應(yīng)該明白將有一個形狀圖層灌曙,應(yīng)該有calayershapelayer類進(jìn)行處理菊碟。calayershapelayer類繼承calayer,在這個層上將會繪制各種形狀的圖形在刺。

用一個頭像示意圖的分層效果圖

圖層的分層效果.png

額外增加的知識點(diǎn):1.photoLayer.mask = maskLayer逆害,標(biāo)示的是將mask layer作為photo layer的遮罩層。
2.@IBInspectable和@IBDesignable的作用是讓storyboard控件圖片的顯示與代碼的設(shè)置保持一致

把這3個圖層添加到涂層上的核心代碼:

 // 當(dāng)avatarview 對象呈現(xiàn)在視圖上的時候蚣驼,會調(diào)用didMoveToWindow方法魄幕。讓layer呈現(xiàn)到視圖上
  override func didMoveToWindow() {
    layer.addSublayer(photoLayer)
    photoLayer.mask = maskLayer
    layer.addSublayer(circleLayer)
    addSubview(label)
  }
//layout方法中可以知道每一個層都將是一個矩形
override func layoutSubviews() {
    //Size the avatar image to fit
    photoLayer.frame = CGRect(
      x: (bounds.size.width - image.size.width + lineWidth)/2,
      y: (bounds.size.height - image.size.height - lineWidth)/2,
      width: image.size.width,
      height: image.size.height)
    //Draw the circle
    circleLayer.path = UIBezierPath(ovalInRect: bounds).CGPath
    circleLayer.strokeColor = UIColor.whiteColor().CGColor
    circleLayer.lineWidth = lineWidth
    circleLayer.fillColor = UIColor.clearColor().CGColor
    //Size the layer
    maskLayer.path = circleLayer.path
    maskLayer.position = CGPoint(x: 0.0, y: 10.0)
    //Size the label
    label.frame = CGRect(x: 0.0, y: bounds.size.height + 10.0, width: bounds.size.width, height: 24.0)
  }

截下來就要開始做動畫了,實現(xiàn)一個頭像發(fā)生碰撞的動畫

游戲開始的時候搜索對手的動畫核心代碼:
思路:頭像從原始位置到達(dá)碰撞點(diǎn)颖杏,當(dāng)碰撞的動畫完成之后纯陨,返回到原始的位置,接著在重復(fù)做上述動畫。

首先為在搜索對手需要準(zhǔn)備的偏移量翼抠,變形大小咙轩,形變寫入一個方法里,將它傳入頭像視圖里做動畫

func searchForOpponent(){
        let avatarSize = myAvatar.frame.size
        let bounceXOffset: CGFloat = avatarSize.width/1.9//設(shè)置一個水平方向上的反彈偏移量
        let morphSize = CGSize(
            width: avatarSize.width * 0.85,
            height: avatarSize.height * 1.1)//設(shè)置了頭像的變形大小
      //計算2個頭像到達(dá)反彈點(diǎn)時發(fā)生輕微的碰撞阴颖,計算出左右2個反彈點(diǎn)活喊,然后通過動畫將其分開
        let rightBouncePoint = CGPoint(
            x: view.frame.size.width/2.0 + bounceXOffset,
            y: myAvatar.center.y)
        let leftBouncePoint = CGPoint(
            x: view.frame.size.width/2.0 - bounceXOffset,
            y: myAvatar.center.y)    
        myAvatar.bounceOffPoint(rightBouncePoint, morphSize: morphSize)
/*第一個參數(shù)是頭像發(fā)生碰撞的點(diǎn),
         第二個參數(shù)是頭像發(fā)生碰撞時的變形大小*/
     opponentAvatar.bounceOffPoint(leftBouncePoint, morphSize: morphSize)
        delay(seconds: 4.0, completion: foundOpponent)
    }

動畫代碼:

  func bounceOffPoint(bouncePoint: CGPoint,             morphSize: CGSize) {

       let originalCenter = center

      UIView.animateWithDuration(animationDuration, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.0, options: [], animations: {
            self.center = bouncePoint
        }, completion: {_ in
            
        })
        
         UIView.animateWithDuration(animateWithDuration, delay: animateWithDuration, usingSpringWithDamping: 0.7,initialSpringVelocity: 1.0, options: [], animations: {
           self.center = originalCenter
            
        },completion: {
            delay(seconds: 0.1){
                self.bounceOffPoint(bouncePoint, morphSize: morphSize)
            }
        })
    }

截下來做2個頭像接觸之后的一個變形動畫

思路:根據(jù)左右2個頭像的frame分別設(shè)置動畫量愧,應(yīng)為2個頭像發(fā)生碰撞變形后的frame是不同的钾菊。對每個頭像進(jìn)行變形動畫

核心代碼:

let morphedFrame = (originalCenter.x >  bouncePoint.x) ?
            CGRect(x: 0.0, y: bounds.height - morphSize.height,width: morphSize.width, height: morphSize.height):
            CGRect(x: bounds.width - morphSize.width,
                   y: bounds.height - morphSize.height,
                   width: morphSize.width, height: morphSize.height)

        let morphAnimation = CABasicAnimation(keyPath: "path")
        morphAnimation.duration = animationDuration
        morphAnimation.toValue =  UIBezierPath(ovalInRect: morphedFrame).CGPath
        morphAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)//緩出的方式進(jìn)行動畫
        circleLayer.addAnimation(morphAnimation, forKey:nil)
        maskLayer.addAnimation(morphAnimation, forKey: nil)

接下來應(yīng)該是現(xiàn)實對手的數(shù)據(jù),并且改變頁面上方狀態(tài)label的顯示文字

思路:在開始動畫的過程中偎肃,對對手的頭像圖片和label的狀態(tài)進(jìn)行顯示结缚。
核心代碼如下:

//搜索中的方法
 func foundOpponent() {
        status.text = "Connecting..."
        
        opponentAvatar.image = UIImage(named: "avatar-2")
        opponentAvatar.name = "Ray"
        
        delay(seconds: 4.0, completion: connectedToOpponent)
    }
    
    func connectedToOpponent() {
        myAvatar.shouldTransitionToFinishedState = true//
        opponentAvatar.shouldTransitionToFinishedState = true
        
        delay(seconds: 1.0, completion: completed)
    }
   
//最終的顯示狀態(tài) 
    func completed() {
        status.text = "Ready to play"
        UIView.animateWithDuration(0.2) {
            self.vs.alpha = 1.0//顯示頭像之間的label
            self.searchAgain.alpha = 1.0//顯示開始游戲的button按鈕
        }
    }
}

要實現(xiàn)的效果基本上是已經(jīng)出來了,還差一個就是怎樣才能讓搜索狀態(tài)信息完成之后使動畫結(jié)束呢

思路:用一個變量標(biāo)示是否結(jié)束動畫软棺,如是結(jié)束動畫红竭,執(zhí)行將動畫停止的方法,不在持續(xù)調(diào)用動畫的方法

核心代碼:
動畫完成后的判斷:

if self.shouldTransitionToFinishedState {
            
                self.animateToSquare()
            }

結(jié)束動畫:

func animateToSquare() {
        isSquare = true
        
        let squarePath = UIBezierPath(rect: bounds).CGPath
        let morph = CABasicAnimation(keyPath: "path")
        morph.duration = 0.25
        morph.fromValue = circleLayer.path
        morph.toValue = squarePath
        
        circleLayer.addAnimation(morph, forKey: nil)
        maskLayer.addAnimation(morph, forKey: nil)
        
        circleLayer.path = squarePath
        maskLayer.path = squarePath
    }

不在調(diào)用動畫方法的判斷:

if !self.isSquare{
                    self.bounceOffPoint(bouncePoint, morphSize: morphSize)
                }

效果圖:

擠壓動畫.gif

下載地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末喘落,一起剝皮案震驚了整個濱河市茵宪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瘦棋,老刑警劉巖稀火,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異赌朋,居然都是意外死亡凰狞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進(jìn)店門沛慢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赡若,“玉大人,你說我怎么就攤上這事团甲∮舛” “怎么了?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵躺苦,是天一觀的道長身腻。 經(jīng)常有香客問我,道長匹厘,這世上最難降的妖魔是什么嘀趟? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮愈诚,結(jié)果婚禮上她按,老公的妹妹穿的比我還像新娘牛隅。我一直安慰自己,他們只是感情好尤溜,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布倔叼。 她就那樣靜靜地躺著,像睡著了一般宫莱。 火紅的嫁衣襯著肌膚如雪丈攒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天授霸,我揣著相機(jī)與錄音巡验,去河邊找鬼。 笑死碘耳,一個胖子當(dāng)著我的面吹牛显设,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播辛辨,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼捕捂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了斗搞?” 一聲冷哼從身側(cè)響起指攒,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎僻焚,沒想到半個月后允悦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡虑啤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年隙弛,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狞山。...
    茶點(diǎn)故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡全闷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出铣墨,到底是詐尸還是另有隱情室埋,我是刑警寧澤,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布伊约,位于F島的核電站,受9級特大地震影響孕蝉,放射性物質(zhì)發(fā)生泄漏屡律。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一降淮、第九天 我趴在偏房一處隱蔽的房頂上張望超埋。 院中可真熱鬧搏讶,春花似錦、人聲如沸霍殴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽来庭。三九已至妒蔚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間月弛,已是汗流浹背肴盏。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帽衙,地道東北人菜皂。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像厉萝,于是被迫代替她去往敵國和親恍飘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評論 2 348

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫谴垫、插件章母、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,059評論 4 62
  • 1.日志可讀性好,容易定位問題 2.接口錯誤碼統(tǒng)一弹渔,自解釋胳施,根據(jù)錯誤碼,一步定位到原因 3.接口 需要做強(qiáng)校驗肢专,統(tǒng)...
    柳菲閱讀 119評論 0 0
  • 亚洲A日韩AV无卡,小受高潮白浆痉挛av免费观看,成人AV无码久久久久不卡网站,国产AV日韩精品