Swift_ios_UIView動畫,CA核心動畫那些事(2)

秒學SWIFT

花了將近一周的時間去學習ios動畫,因為對于一個ios開發(fā)者來說,動畫內(nèi)容絕對是一門必修課。聽了不少課,也看了不少文章,終于對動畫有了初步的了解和自己的一些小總結(jié)。但是傻傻笨笨的我,給自己挖了一個坑,為了填這個坑花了快兩天時間,真夠笨的!不過最終還是完美解決,小小成就感就來了!

關(guān)于動畫,網(wǎng)上流傳著許許多多的文章,基本上都適合初學者入門。那些文章大概思路都是這樣的:
1.介紹什么是動畫
2.動畫可以分為UIView動畫和CA動畫。(其他動畫暫時忽略)
3.UIView動畫分為常規(guī)模式和閉包模式?,F(xiàn)在主要用閉包模式。
4.UIView閉包模式有基本“杜蕾斯”動畫,杜蕾斯彈性動畫,轉(zhuǎn)場動畫,關(guān)鍵幀動畫。
5.CA動畫有基本動畫,轉(zhuǎn)場動畫,關(guān)鍵幀動畫,組動畫,彈性動畫。
6.UIView動畫和CA動畫的關(guān)系,即UIView動畫是CA動畫的封裝。各有優(yōu)勢各有特色。

無可否認的是這些對自己在初步認識動畫階段,起到了很大的幫助作用,起碼讓自己對動畫有個大概的了解。但是僅僅這些,還是會讓初學者掉進坑里,比如我。所以學習動畫以后的總結(jié)經(jīng)驗,就不可或缺了。這才不會讓自己第二次掉進同一個坑。待會我要記錄下自己怎么掉坑,填坑的。

我是先學習CA動畫的,明白了CA動畫能夠細微調(diào)整的意義,也見識了CA動畫是怎么讓開發(fā)者去掌控每一個環(huán)節(jié)的。這個過程中我也筆記了基礎(chǔ)的知識:(有一部分摘抄,一部分是自己總結(jié))

//CAAnimation:
//所有動畫對象的父類,負責控制動畫的持續(xù)時間和速度,是個抽象類,不能直接使用,應(yīng)該使用它具體的子類
//duration:動畫的持續(xù)時間
//repeatCount:動畫的重復次數(shù)
//repeatDuration:動畫的重復時間
//removedOnCompletion:默認為YES,代表動畫執(zhí)行完畢后就從圖層上移除,圖形會恢復到動畫執(zhí)行前的狀態(tài)。如果想讓圖層保持顯示動畫執(zhí)行后的狀態(tài),那就設(shè)置為NO,不過還要設(shè)置fillMode為kCAFillModeForwards
//fillMode:決定當前對象在非active時間段的行為.比如動畫開始之前,動畫結(jié)束之后
//beginTime:可以用來設(shè)置動畫延遲執(zhí)行時間,若想延遲2s,就設(shè)置為CACurrentMediaTime()+2,CACurrentMediaTime()為圖層的當前時間
//timingFunction:速度控制函數(shù),控制動畫運行的節(jié)奏
//delegate:動畫代理
//keyPath: 通過指定CALayer的一個屬性名稱達到相應(yīng)的動畫效果,比如說,指定"position"為keyPath,就修改CALayer的position屬性值,以達到平移的動畫效果


//A. CGAffineTransform
//從CG就可以看出它是屬于Core Graphics的東西,實際上UIView的transform屬性就是CGAffineTransform類型,用它可以做二維平面上的縮放、旋轉(zhuǎn)、平移。
//B.CATransform3D(layer)
//它可以做到讓圖層在三維空間內(nèi)平移、旋轉(zhuǎn)等。

  • CABasicAnimation動畫比較簡單,不做多介紹,只留筆記重點。如果有誤,歡迎指正。
    //A.CABasicAnimation
    //CABasicAnimation(keyPath: "transform")可以實現(xiàn)2D和3D動畫。取決于keyPath。
    //如果keyPath: "transform" 則是3D動畫。rotation屬性才能體現(xiàn)3D效果
    //如果keyPath: "transform.rotation" 則是2D動畫。
    //2D動畫變換前的原始狀態(tài)。view.transform = CGAffineTransformIdentity
    //3D動畫變換前的原始狀態(tài)view.layer.transform = CATransform3DIdentity
  • CAKeyFrameAnimation動畫功能強大,有必要對其屬性闡述一下。
    //B. CAKeyFrameAnimation
    //CApropertyAnimation的子類,跟CABasicAnimation的區(qū)別是: CABasicAnimation只能從一個數(shù)值(fromValue)變到另一個數(shù)值(toValue),而CAKeyframeAnimation會使用一個NSArray保存這些數(shù)值
    //屬性解析:
    //values:就是上述的NSArray對象。里面的元素稱為”關(guān)鍵幀”(keyframe)。動畫對象會在指定的時間(duration)內(nèi),依次顯示values數(shù)組中的每一個關(guān)鍵幀
    //path:可以設(shè)置一個CGPathRef\CGMutablePathRef,讓層跟著路徑移動。path只對CALayer的anchorPoint和position起作用。如果你設(shè)置了path,那么values將被忽略
    //keyTimes:可以為對應(yīng)的關(guān)鍵幀指定對應(yīng)的時間點,其取值范圍為0到1.0,keyTimes中的每一個時間值都對應(yīng)values中的每一幀.當keyTimes沒有設(shè)置的時候,各個關(guān)鍵幀的時間是平分的
    //CABasicAnimation可看做是最多只有2個關(guān)鍵幀的CAKeyframeAnimation
    //這里有必要提供一下快速構(gòu)建values的方法
    let arr = [(20,30),(100,100),(100,300),(50,300)].map{ (x:Int,y:Int) -> NSValue in
    NSValue(CGPoint: CGPoint(x: x, y: y))

      }
      
      keyAnimate.values = arr
    
  • CAAnimationGroup也比較簡單,就是對多個動畫的組合。
    //C. CAAnimationGroup
    //CAAnimation的子類,可以保存一組動畫對象,將CAAnimationGroup對象加入層后,組中所有動畫對象可以同時并發(fā)運行.支持多個動畫組合。
    //屬性解析:
    //animations:用來保存一組動畫對象的NSArray
    //默認情況下,一組動畫對象是同時運行的,也可以通過設(shè)置動畫對象的beginTime屬性來更改動畫的開始時間

  • CATransition是一個比較有意思的動畫,轉(zhuǎn)場效果挺多。
    //D. CATransition
    //CAAnimation的子類,用于做轉(zhuǎn)場動畫,能夠為層提供移出屏幕和移入屏幕的動畫效果。iOS比Mac OS X的轉(zhuǎn)場動畫效果少一點
    //UINavigationController就是通過CATransition實現(xiàn)了將控制器的視圖推入屏幕的動畫效果
    //屬性解析:
    //type:動畫過渡類型
    /*
    fade
    push
    moveIn
    reveal
    cube
    oglFlip
    suckEffect
    rippleEffect
    pageCurl
    pageUnCurl
    cameraIrisHollowOpen
    cameraIrisHollowClose
    */
    //subtype:動畫過渡方向
    //startProgress:動畫起點(在整體動畫的百分比)
    //endProgress:動畫終點(在整體動畫的百分比)

  • CASpringAnimation是彈性動畫,能夠表現(xiàn)出非常性感細膩的效果
    //E.CASpringAnimation
    屬性:默認值
    damping:10.0
    mass :1.0
    stiffness:100.0
    initialVelocity:0.0

     let sprintAni = CASpringAnimation(keyPath: "position.y")
      sprintAni.damping = 10
      sprintAni.mass = 5
      sprintAni.stiffness = 50
      sprintAni.initialVelocity = 3
      
      sprintAni.duration = 2
      sprintAni.toValue = 300
          
      sprintAni.fillMode = kCAFillModeForwards
      sprintAni.removedOnCompletion = false
      
      yourView.layer.addAnimation(sprintAni, forKey: "anykey")
    

以上是CA動畫的類型,我學習完它再去學UIView動畫,所以知道UIView動畫其實就是CA動畫的封裝,優(yōu)點是快捷方便,UIView的彈性動畫完美體現(xiàn)了這點。缺點是不能細微調(diào)整。這里不作UIView的詳細介紹。

雖然UIView動畫是對CA核心動畫的封裝,但還是有必要對他們加以總結(jié),這可是目前在網(wǎng)上找不到的寶貴經(jīng)驗哦?。ń?jīng)驗可能有誤,歡迎指正)

//UIView的動畫跟CAAnimation動畫的異同:
//1.都能控制動畫開始執(zhí)行時刻。uiview的delay。CA中的beginTime。
//2.都能在動畫結(jié)束后實現(xiàn)控制。uiview有閉包。CA中有代理函數(shù)didFinish。
//3.uiView有彈性動畫和關(guān)鍵幀動畫,CA中也有,而且更為豐富。
//4.uiView組合動畫用cgaffinetransformconcat。CA中用CAanimationGroup,并支持多組合。
//    uiview 的多組合則可以通過創(chuàng)建多個uiview.animation來實現(xiàn)。多是指兩個以上。
//    這里的組合是指為同一個對象的不同屬性進行組合。
//    如果是不同對象要實現(xiàn)同一個動畫,則直接在uiview的內(nèi)容中添加。或者直接在CA中賦予多個對象的layer。
//5.uiView實現(xiàn)2D或者3D動畫,取決于里面設(shè)置的動畫屬性。若設(shè)置的是layer層,則可以實現(xiàn)3D動畫。(rotation屬性可以體現(xiàn))
//  CA動畫則取決于key。如果是transform,則可以3D.如果是transform.rotation,則可以是2D。
//    CA中transform屬性有rotation,scale,translation。
//    CA中key還可以是bounds,position,opacity。這里的position等價于uiview的center。
//6.uiview動畫完畢之后屬性已經(jīng)更改。CA動畫則不會改變實際位置,即使表面改變了。

下面我則要記錄下我在學習UIView動畫的時候是怎么給自己挖坑的,并怎么最終把坑填上獲得小小成就感的。其實當完美解決問題的那一刻,發(fā)現(xiàn)代碼是如此的簡單,可就為了那一段代碼,讓我費勁了力氣,花盡了腦汁才得以解決。只怪自己經(jīng)驗不足咯!都說怪我咯希望能幫助到有同樣困惑的人兒

關(guān)鍵字:中斷,終止,中止,取消,停止UIView動畫

問題發(fā)現(xiàn):

  • UIView動畫在duration內(nèi),也就是正在執(zhí)行的過程中,我再次觸發(fā)了同樣的動畫,此時動畫就會不正常顯示。

問題起源:

  • 發(fā)現(xiàn)這個問題的時候,其實很多人就想到可能會轉(zhuǎn)用CA動畫去實現(xiàn),因為CA動畫在執(zhí)行過程中,再次觸發(fā)的話,它會重新來過,并不會出現(xiàn)錯亂。我也是想到了這個辦法,但是我就想知道在UIView動畫中怎么解決這個問題的!所以問題就這樣起源了~

問題解決:

  • 1.首先肯定是想到再次觸發(fā)前先把上一次動畫取消掉,想想應(yīng)該是很快就把問題給解決了吧,因為從邏輯上并沒有什么錯誤。于是我觸發(fā)的前面加了一句self.textView?.layer.removeAllAnimations()
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {      
        self.textView?.layer.removeAllAnimations()
        self.animation()   
    }

可是問題真的解決了嗎?當然不是。添加后的現(xiàn)象是我再次觸發(fā)時,動畫立馬停止了??雌饋砗竺鎠elf.animation()并沒有執(zhí)行一樣。

  • 2.于是我開始請教百度叫獸,失望的是幾乎把百度翻了個遍,也沒找到答案。納悶了,難道只有我才遇到這個問題嗎?只有我經(jīng)驗淺腦子笨才掉這個坑嗎?唯一在網(wǎng)上找到一個相關(guān)的文章《如何中止UIView動畫?》
    http://samwei12.gitcafe.io/2015/09/09/%E5%A6%82%E4%BD%95%E5%8F%96%E6%B6%88UIView%E5%8A%A8%E7%94%BB/ 簡書上也有。又是OC版本的,OC就OC吧,抱著一線希望把OC代碼轉(zhuǎn)換成Swift后,一執(zhí)行丫的還是不管用!夢想再次破滅~

  • 3.這時想到了swift交流群,在群上一問三不知,這該如何是好。大神都不出來幫我~

  • 4.還是自己找原因吧。在UIView動畫執(zhí)行完的閉包里面添加一些打印信息吧。于是我添加了print("finish")
    { (finish:Bool) -> Void in
    if finish {print("finish")}
    }
    此時我在第二次又觸發(fā)動畫的時候發(fā)現(xiàn),只打印了一次finish!這finish是第一次動畫執(zhí)行的還是第二次動畫執(zhí)行的?從現(xiàn)象上就很好解釋了,肯定是第二次動畫打印的finish。而且還有一個現(xiàn)象就是,第二次觸發(fā)動畫的時候,立馬就打印finish,這也就是為什么看不到第二次動畫的執(zhí)行!原來本意是要停掉上一次正在執(zhí)行的動畫,再接著執(zhí)行第二次動畫?,F(xiàn)在問題是第二次也被停掉了?。?!到底問題出現(xiàn)在哪里???靈光一閃,突然想到了延時!就是停掉第一次動畫的時候,延時一下,再執(zhí)行第二次動畫看行不行?
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    self.textView?.layer.removeAllAnimations()
    self.performSelector("animation", withObject: nil, afterDelay: 0.3)
    }

  • 5.duang~的一下,成功了!只要在執(zhí)行動畫的前面添加一個細小的延時,就可以完美解決了這個可惡的問題!后面我再測了一下,把afterDelay改成0 ,也同樣成功了,這這又如何解釋,就留給大家吧

問題回首:

  • 解決的代碼非常簡單,可對我來說真的容易么?在沒有百度君簡書君的幫助下,孤軍奮戰(zhàn),血戰(zhàn)到底,我容易么?
有了UIView動畫的填坑經(jīng)驗,我自個再到CA中去解決類似問題就迎刃而解了!什么?剛剛不是說CA中不存在這種問題嗎??這里有必要說明一點,就是當CA動畫是非無止境動畫(就是會停止的動畫),在還沒停止之前再次觸發(fā),是不會發(fā)生這些錯亂問題的。

然而要是CA動畫是個無止境的動畫,也就是如果動畫委托協(xié)議的animationDidStop中再次調(diào)用動畫函數(shù)的話,這時再來個觸發(fā)相同動畫,動畫就是亂得一塌糊涂了!接下來就記錄一下怎么輕松解決這個問題的。
   @IBAction func next(sender: AnyObject) {
    self.transition()
    }

  func transition(){
    let transition = CATransition()
    transition.delegate = self
    //動畫過渡類型
    transition.type = "pageCurl"
    
    //動畫過渡類型方向
    transition.subtype = kCATransitionFromLeft
    
    transition.duration = 1
    
    transition.setValue("second", forKey: "whichAnimation")
    
    self.iv.layer.addAnimation(transition, forKey: nil)
  }

  override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
        switch anim.valueForKey("whichAnimation") as! String{
        case "one"    :
                        print("hello")         
        case "second" :
                        print("finish")    
                        self.next("repeat")
        default :print("grandre")
        }
  }

這樣的代碼確實能夠運行,能夠循環(huán)調(diào)用動畫,實現(xiàn)無止境。但是問題是當再次點擊按鍵觸發(fā)動畫的話,這代碼的bug就一漏無遺了。

  • 解決初探1:再次觸發(fā)之前,去掉所有動畫。
    @IBAction func next(sender: AnyObject) {
    self.iv.layer.removeAllAnimations()
    self.transition()
    }
    結(jié)果:失敗。原因:self.iv.layer.removeAllAnimations()執(zhí)行后會調(diào)用委托協(xié)議,導致死循環(huán)。

  • 解決初探2:添加“是否自動完成動畫”標志。如果是自動完成一輪動畫,則執(zhí)行委托協(xié)議代碼,如果不是自動完成,則不執(zhí)行。從而避免了死循環(huán)。
    @IBAction func next(sender: AnyObject) {
    ifAutoFinishAnimate = false
    self.iv.layer.removeAllAnimations()//這里沒打印是因為標志置false了
    self.transition()
    }
    func transition(){
    let transition = CATransition()
    transition.delegate = self
    //動畫過渡類型
    transition.type = "pageCurl"

      //動畫過渡類型方向
      transition.subtype = kCATransitionFromLeft
      
      transition.duration = 1
      //        一定要在加載動畫之前設(shè)置setValue
      transition.setValue("second", forKey: "whichAnimation")
      
      self.iv.layer.addAnimation(transition, forKey: nil)
      ifAutoFinishAnimate = true  //動畫完成之后恢復標志,才能執(zhí)行委托協(xié)議代碼
    }
      override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
       if ifAutoFinishAnimate == true{
          switch anim.valueForKey("whichAnimation") as! String{
          case "one" :print("hello")
          case "second" :print("finish")
              self.next("2")
          default :print("baba")
          }
        }
     }
    

    結(jié)果:失??!現(xiàn)象是“根本停不下來!”此時原因應(yīng)該就是UIView動畫的原因一樣了!


  • 解決初探3:添加延時。
    @IBAction func next(sender: AnyObject) {
    ifAutoFinishAnimate = false
    self.iv.layer.removeAllAnimations()//這里沒打印是因為標志置false了
    performSelector("transition", withObject: nil, afterDelay: 0.3)
    }
    結(jié)果:Done!完美解決!這經(jīng)驗真管用!afterDelay改成0,這次就不行咯!至于為什么,同樣留給大家思考吧。所以記錄所遇到的問題并加以總結(jié)是對自己非常有幫助的。

謹以此文章記錄自己在學習動畫路上遇到的問題,也希望能夠通過分享總結(jié),分享故事幫助到碰上同樣問題的人兒。
最后編輯于
?著作權(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)容

  • Core Animation Core Animation,中文翻譯為核心動畫,它是一組非常強大的動畫處理API,...
    45b645c5912e閱讀 3,158評論 0 21
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復雜,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,694評論 6 30
  • 顯式動畫 顯式動畫,它能夠?qū)σ恍傩宰鲋付ǖ淖远x動畫,或者創(chuàng)建非線性動畫,比如沿著任意一條曲線移動。 屬性動畫 ...
    清風沐沐閱讀 2,096評論 1 5
  • 如果想讓事情變得順利,只有靠自己--夏爾·紀堯姆 上一章介紹了隱式動畫的概念。隱式動畫是在iOS平臺創(chuàng)建動態(tài)用戶界...
    夜空下最亮的亮點閱讀 2,102評論 0 1
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復雜,今天將帶大家一窺iOS動畫全貌。在這里你可以看...
    F麥子閱讀 5,270評論 5 13

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