【iOS動(dòng)畫】學(xué)習(xí)筆記第一彈(View Animation)

本文是筆者學(xué)習(xí)iOS動(dòng)畫的一些小總結(jié)茄厘;

View Animation

動(dòng)畫其實(shí)就是UIView基本屬性(animatable)的操作油猫,我們寫動(dòng)畫的時(shí)候稠茂,其實(shí)不需要關(guān)心其中的數(shù)學(xué)計(jì)算,只需要熟悉API的特性即可情妖。

屏幕快照 2017-08-20 22.45.54.png

我們可以看到UIView中的屬性中注明為animatable的睬关,那么這個(gè)屬性就是我們寫動(dòng)畫可以用到的屬性。還有一個(gè)alpha屬性同樣是animatable毡证。

本文中的動(dòng)畫方法都是UIKit為我們封裝好的一些方法电爹,也就是UIView提供的類方法,比如常見的animate(withDuration:animations:),因?yàn)槭?code>UIKit層提供的料睛,所以這些動(dòng)畫的方法都相對(duì)簡(jiǎn)單好用丐箩,沒有涉及到 Core Animation提供的復(fù)雜API。

animate

UIView的一個(gè)extension里都是animate的類方法恤煞,如下圖所示:

屏幕快照 2017-08-20 23.53.18.png

normal

UIViewanimate類方法是最簡(jiǎn)單的動(dòng)畫方法屎勘,相信大家一定都用過。

UIView.animate(withDuration: 0.5, delay: 0.4,
  options: [.repeat, .autoreverse, .curveEaseIn],
  animations: {
    self.password.center.x += self.view.bounds.width
  },
  completion: nil
)

這里想了好久不知道如何去解釋居扒,索性就不去解釋了概漱,反正iOSer能看懂就行??

這里的options倒可以解釋下, 這個(gè)屬性可以告訴UIKit如何去執(zhí)行animations里的操作,是UIViewAnimationOptions類型。常見的有

repeat // 重復(fù)的執(zhí)行`animations`里的操作
curveEaseInOut //類似汽車行駛先加速之后到達(dá)目的地時(shí)減速的效果執(zhí)行動(dòng)畫
curveEaseIn // 汽車加速
curveEaseOut // 汽車減速
curveLinear // 汽車勻速

spring

spring類型的animate類方法相對(duì)于normal類型的增加了彈簧的效果苔货,使動(dòng)畫更加符合現(xiàn)實(shí)中的動(dòng)畫效果犀概。

 UIView.animate(withDuration: 1.5, delay: 0.0, usingSpringWithDamping: 0.2,
      initialSpringVelocity: 0.0, options: [],
      animations: {
        self.loginButton.bounds.size.width += 80.0
      },
      completion: nil
)

方法中usingSpringWithDamping取值為0-1立哑,數(shù)值越大,彈簧效果越不明顯姻灶。

transition

之前的normal和spring都是基于UIViewanimatable屬性的動(dòng)畫铛绰,如果想要給添加view或者移除view做動(dòng)畫的話,就需要使用transition類型的animate類方法來實(shí)現(xiàn)产喉。

UIView.transition(with: animationContainerView,
   duration: 0.33,
   options: [.curveEaseOut, .transitionFlipFromBottom],
   animations: {
     self.animationContainerView.addSubview(newView)
   },
   completion: nil
 )

上述代碼給animationContainerView制造了一個(gè)動(dòng)畫捂掰,當(dāng)有subview添加到animationContainerView中時(shí),動(dòng)畫就會(huì)執(zhí)行曾沈。方法中的options同樣的告訴UIKit如何去執(zhí)行animations里的操作,是UIViewAnimationOptions類型这嚣。常見的有

.transitionFlipFromLeft
.transitionFlipFromRight
.transitionCurlUp
.transitionCurlDown
.transitionCrossDissolve
.transitionFlipFromTop
.transitionFlipFromBottom

當(dāng)我們想替換view時(shí),可以使用下面的方法

UIView.transition(from: oldView, to: newView, duration: 0.33,
  options: .transitionFlipFromTop, completion: nil)

UIKit幫了我們太多??

keyframe

之前的三種類型的動(dòng)畫都是單一效果的塞俱,現(xiàn)實(shí)中的動(dòng)畫大多是有許多步驟的姐帚,此時(shí)如果我們使用completion來連接下一個(gè)動(dòng)畫,代碼會(huì)被嵌套很多層障涯。所以我們可以將每個(gè)單獨(dú)的步驟拆分成一個(gè)個(gè)的Keyframes罐旗,然后用Keyframe動(dòng)畫將各個(gè)單獨(dú)的Keyframes連接起來生成一個(gè)完整的動(dòng)畫。

 UIView.animateKeyframes(withDuration: 1.5, delay: 0.0, animations: { 
            UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.25, animations: { 
                self.planeImage.center.x += 80.0
                self.planeImage.center.y -= 10.0
            })
            
            UIView.addKeyframe(withRelativeStartTime: 0.1, relativeDuration: 0.4, animations: { 
                self.planeImage.transform = CGAffineTransform(rotationAngle: -.pi / 8)
            })
            
            UIView.addKeyframe(withRelativeStartTime: 0.25, relativeDuration: 0.25, animations: { 
                self.planeImage.center.x += 100.0
                self.planeImage.center.y -= 50
                self.planeImage.alpha = 0.0
            })
            
            UIView.addKeyframe(withRelativeStartTime: 0.51, relativeDuration: 0.01, animations: { 
                self.planeImage.transform = .identity
                self.planeImage.center = CGPoint(x: 0.0, y: originalCenter.y)
            })
            
            UIView.addKeyframe(withRelativeStartTime: 0.55, relativeDuration: 0.45, animations: { 
                self.planeImage.alpha = 1.0
                self.planeImage.center = originalCenter
            })
            
        }, completion: nil)

上例寫了一個(gè)飛機(jī)起飛到著陸的動(dòng)畫唯蝶,addKeyframe里的withRelativeStartTimerelativeDuration都是相對(duì)于animateKeyframeswithDuration來計(jì)算的九秀。

auxiliary views

 // cube animation
    func cubeTransition(label: UILabel, text: String, direction: AnimationDirection) {
        let auxLabel = UILabel(frame: label.frame)
        auxLabel.text = text
        auxLabel.font = label.font
        auxLabel.textAlignment = label.textAlignment
        auxLabel.textColor = label.textColor
        auxLabel.backgroundColor = label.backgroundColor
        
        let auxLabelOffset = CGFloat(direction.rawValue) * label.frame.size.height / 2.0
        auxLabel.transform = CGAffineTransform(scaleX: 1.0, y: 0.1)
         .concatenating(CGAffineTransform(translationX: 0.0, y: auxLabelOffset))
        label.superview?.addSubview(auxLabel)
        
        UIView.animate(withDuration: 0.5, delay: 0.0, options: [.curveEaseOut], animations: { 
            auxLabel.transform = .identity
            label.transform = CGAffineTransform(scaleX: 1.0, y: 0.1)
             .concatenating(
                CGAffineTransform(translationX: 0.0, y: -auxLabelOffset)
            )
        }, completion: { _ in
            label.text = auxLabel.text
            label.transform = .identity
            auxLabel.removeFromSuperview()
        })
    }

上述代碼寫了一個(gè)label立方體翻轉(zhuǎn)的效果,但其實(shí)不是真的3D效果粘我,這里使用到了一個(gè)輔助的label鼓蜒,對(duì)兩個(gè)label同時(shí)動(dòng)畫,最后移除這個(gè)輔助label征字,從而達(dá)到了立方體翻轉(zhuǎn)的效果都弹。

Auto Layout

之前的動(dòng)畫都是設(shè)置 animatable的屬性,UIKit幫助我們實(shí)現(xiàn)對(duì)應(yīng)的動(dòng)畫效果柔纵。但是現(xiàn)在我們大多更多的使用Auto Layout來進(jìn)行布局界面缔杉,此時(shí)上面的幾種動(dòng)畫方法同樣也是有效的锤躁,只是此時(shí)我們操作的是約束搁料。

UIViewPropertyAnimator 更新于2017-11-11

UIViewPropertyAnimator 是iOS10新出的一個(gè)動(dòng)畫相關(guān)的類,通過這個(gè)類我們可以簡(jiǎn)單的創(chuàng)建更加易于控制的view animation系羞,也就是說此時(shí)我們?cè)谝恍﹫?chǎng)景中可以不去創(chuàng)建layer animation郭计,通過UIViewPropertyAnimator也可以完成需要。

UIViewPropertyAnimator和之前的UIView.animate系列方法是相輔相成的椒振,也就是說有些簡(jiǎn)單的情況昭伸,我們只需要使用UIView.animate系列方法就可以了,沒有必要去使用UIViewPropertyAnimator澎迎。

一個(gè)簡(jiǎn)單的UIViewPropertyAnimator創(chuàng)建的動(dòng)畫如下:

let scale = UIViewPropertyAnimator(duration: 0.33, curve: .easeIn)
   // addAnimations 也可以添加之前的上文所說的keyFrame animation等
    scale.addAnimations {
      view.alpha = 1.0
    }
    scale.addAnimations({
      view.transform = CGAffineTransform.identity
    }, delayFactor: 0.33) // 這里的delayFactor是一個(gè)相對(duì)比例(0-1)庐杨,是相對(duì)于動(dòng)畫剩下的時(shí)間选调,這樣就保證了延遲的時(shí)間不會(huì)超過總時(shí)間
    scale.addCompletion {_ in
      print("ready")
    }

各種不同的animator 可以封裝在單獨(dú)的一個(gè)類,這樣不同的view如果想要?jiǎng)?chuàng)建相同的動(dòng)畫直接調(diào)用方法然后start即可灵份。

animation timing

UIViewPropertyAnimator默認(rèn)提供了以下的curve選擇:

public enum UIViewAnimationCurve : Int {

    
    case easeInOut // slow at beginning and end

    case easeIn // slow at beginning

    case easeOut // slow at end

    case linear
}

其實(shí)這些curve都是控制兩個(gè)control point形成的貝塞爾曲線仁堪,具體可以去這個(gè)網(wǎng)站實(shí)際體驗(yàn)下curve

UIViewPropertyAnimator提供了自定義這兩個(gè)control point的方法填渠,可以讓我們自定義timing 效果弦聂。

  public convenience init(duration: TimeInterval, controlPoint1 point1: CGPoint, controlPoint2 point2: CGPoint, animations: (() -> Swift.Void)? = nil)

除了使用自定義control point的方式來自定義timing,我們還可以通過下面這個(gè)方法來為animator提供自定義的timing方式:

public init(duration: TimeInterval, timingParameters parameters: UITimingCurveProvider)

UITimingCurveProvider是一個(gè)協(xié)議氛什,UIKit提供了兩個(gè)已經(jīng)遵守該協(xié)議的類莺葫,我們可以方便的拿來使用。
UICubicTimingParameters and UISpringTimingParameters. 例如下面這個(gè)spring timing:

 let spring = UISpringTimingParameters(dampingRatio: 0.55)
    
 let animator = UIViewPropertyAnimator(duration: 1.0, timingParameters: spring)

這樣這個(gè)animator的動(dòng)畫運(yùn)行時(shí)就是彈簧效果了枪眉。

animation state

因?yàn)閁IViewPropertyAnimator可以創(chuàng)建##易于控制##的動(dòng)畫捺檬,所以UIViewPropertyAnimator可以讓我們知道現(xiàn)在動(dòng)畫的狀態(tài),以下是三個(gè)主要的狀態(tài)屬性:

1.isRunning(Bool): animator 的動(dòng)畫是否正在運(yùn)行贸铜,默認(rèn)是false欺冀,當(dāng)調(diào)用`startAnimation`后變?yōu)閠rue;
2.isReversed(Bool): animator 的動(dòng)畫執(zhí)行順序萨脑,默認(rèn)是false隐轩,當(dāng)設(shè)置為true后,動(dòng)畫會(huì)反方向執(zhí)行渤早,此時(shí)才改變沒有效果职车,也就是只能一次性設(shè)置;
3.state: animator 動(dòng)畫的狀態(tài)鹊杖,具體見下圖:
屏幕快照 2017-11-11 16.57.24.png

fractionComplete可以接受一個(gè)animator的完成百分比悴灵,達(dá)到一種可交互的動(dòng)畫,類似3Dtouch 的重按動(dòng)畫效果骂蓖;

ViewController Transition Animation

同樣的正是因?yàn)閁IViewPropertyAnimator可以讓我們控制動(dòng)畫的一系列狀態(tài)积瞒,我們也可以使用它來實(shí)現(xiàn)控制器的可交互切換動(dòng)畫,下面方法是iOS10中UIViewControllerAnimatedTransitioning協(xié)議中新增的一個(gè)方法登下,允許提供一個(gè)animator:

func interruptibleAnimator(using transitionContext:
  UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating

總的來說茫孔,UIViewPropertyAnimator是一個(gè)中間產(chǎn)物,為我們提供了多一種的選擇被芳,不及UIView.animate 來的簡(jiǎn)單缰贝,不及Layer Animation的全面。

最后

未完待續(xù)第二彈

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末畔濒,一起剝皮案震驚了整個(gè)濱河市剩晴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌侵状,老刑警劉巖赞弥,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件毅整,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡绽左,警方通過查閱死者的電腦和手機(jī)毛嫉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妇菱,“玉大人承粤,你說我怎么就攤上這事〈惩牛” “怎么了辛臊?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)房交。 經(jīng)常有香客問我彻舰,道長(zhǎng),這世上最難降的妖魔是什么候味? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任刃唤,我火速辦了婚禮,結(jié)果婚禮上白群,老公的妹妹穿的比我還像新娘尚胞。我一直安慰自己,他們只是感情好帜慢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布笼裳。 她就那樣靜靜地躺著,像睡著了一般粱玲。 火紅的嫁衣襯著肌膚如雪躬柬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天抽减,我揣著相機(jī)與錄音允青,去河邊找鬼。 笑死卵沉,一個(gè)胖子當(dāng)著我的面吹牛颠锉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播偎箫,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼木柬,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼皆串!你這毒婦竟也來了淹办?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤恶复,失蹤者是張志新(化名)和其女友劉穎怜森,沒想到半個(gè)月后速挑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡副硅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年姥宝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恐疲。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡腊满,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出培己,到底是詐尸還是另有隱情碳蛋,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布省咨,位于F島的核電站肃弟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏零蓉。R本人自食惡果不足惜笤受,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望敌蜂。 院中可真熱鬧箩兽,春花似錦、人聲如沸章喉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽囊陡。三九已至芳绩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間撞反,已是汗流浹背妥色。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留遏片,地道東北人嘹害。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像吮便,于是被迫代替她去往敵國(guó)和親笔呀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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