隱式動(dòng)畫

一般我們?cè)谧鰟?dòng)畫的時(shí)弥雹,會(huì)使用到 CAAnimation 的相關(guān)類鹦筹,通過 CALayer 的 addAnimation:forKey: 方法秋秤,添加動(dòng)畫效果介衔,這種動(dòng)畫稱為顯式動(dòng)畫恨胚。還有一種動(dòng)畫被稱為隱式的動(dòng)畫,在沒有主動(dòng)添加動(dòng)畫代碼時(shí)炎咖,會(huì)自動(dòng)的產(chǎn)生動(dòng)畫效果赃泡。

我們知道 UIView 的背后,有 CALayer 作為內(nèi)容的顯示乘盼,CALayer 類似于 UIView 也具有樹型結(jié)構(gòu)急迂,可以單獨(dú)的創(chuàng)建。單獨(dú)的創(chuàng)建 CALayer 實(shí)例蹦肴,并修改它的某些屬性僚碎,會(huì)神奇的出現(xiàn)動(dòng)畫效果。

override func viewDidLoad() {
    super.viewDidLoad()   
    
    animationLayer = CALayer()
    animationLayer?.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
    animationLayer?.backgroundColor = UIColor.red.cgColor
    view.layer.addSublayer(animationLayer!)
}
    
@IBAction func move() {
    let centerX: CGFloat = CGFloat(Int(arc4random()) % 375)
    let centerY: CGFloat = CGFloat(Int(arc4random()) % 667)
    let center = CGPoint(x: centerX, y: centerY)
    animationLayer?.position = center
}

上述代碼使用 CALayer 創(chuàng)建一個(gè)紅色的正方形阴幌,并隨機(jī)的修改它的位置勺阐。效果是:

Moving.gif

修改 CALayer 的 position卷中,它沒有立即出現(xiàn)在目標(biāo)位置,而會(huì)有過渡的動(dòng)畫效果渊抽,該過程為 0.25 秒蟆豫,這就是所謂的隱式動(dòng)畫。

隱式動(dòng)畫的背后懒闷,存在事務(wù)的概念十减,任何一個(gè) animatable 屬性的修改,都會(huì)默認(rèn)創(chuàng)建一個(gè) CATransaction 的事務(wù)愤估,來配置動(dòng)畫的參數(shù)帮辟。重寫 CATransaction 可以覆蓋默認(rèn)的動(dòng)畫效果。

將動(dòng)畫時(shí)間修改為五秒:

CATransaction.begin()
CATransaction.setAnimationDuration(5)
animationLayer?.position = center
CATransaction.commit()

替換成上述的代碼段玩焰,移動(dòng)的效果變慢了由驹。另外,還可以用 CATransaction.setDisableActions(true) 方法直接禁用隱式動(dòng)畫昔园。需要注意的是蔓榄,修改隱式動(dòng)畫效果的代碼,都必須要在 begin()commit() 之間默刚,并且成對(duì)出現(xiàn)甥郑。

CATransaction 沒有實(shí)例方法,它像個(gè)神秘的配置工具類荤西。當(dāng)嵌套的使用 CATransaction 時(shí)壹若,它以棧式結(jié)構(gòu)管理。執(zhí)行 begin 的時(shí)皂冰,會(huì)將后面的配置信息入棧;當(dāng)?shù)?commit 時(shí)养篓,出棧配置信息秃流,處于它們之間的屬性修改是原子的,等下一次 RunLoop 到來時(shí)柳弄,開始執(zhí)行動(dòng)畫舶胀。

舉一個(gè)嵌套使用的例子:

CATransaction.begin()
CATransaction.setAnimationDuration(1)
let centerX: CGFloat = CGFloat(Int(arc4random()) % 375)
let centerY: CGFloat = CGFloat(Int(arc4random()) % 667)
let center = CGPoint(x: centerX, y: centerY)
animationLayer?.position = center
    
CATransaction.begin()
CATransaction.setAnimationDuration(5)
let random: CGFloat = CGFloat(Int(arc4random()) % 4)
let transform = CGAffineTransform(rotationAngle: CGFloat(M_PI_4) * random)
animationLayer?.setAffineTransform(transform)
CATransaction.commit()
        
CATransaction.commit()

外層是移動(dòng)的效果,內(nèi)層是旋轉(zhuǎn)效果碧注,內(nèi)層的效果會(huì)先被提交執(zhí)行嚣伐。

仔細(xì)觀察動(dòng)畫效果,肉眼發(fā)現(xiàn)旋轉(zhuǎn)和移動(dòng)幾乎是同時(shí)開始的萍丐,它們分明是按順序提交的兩段代碼轩端,為什么會(huì)同時(shí)執(zhí)行?

這時(shí)候就需要了解下 CALayer 動(dòng)畫的形成原理逝变,在 CALayer 的頭文件里面有兩個(gè)方法基茵,modelLayer()presentationLayer()它們分別叫模型樹和呈現(xiàn)樹奋构,文檔已有詳細(xì)說明。

當(dāng)我們開始動(dòng)畫的時(shí)候拱层,我們必須要先確定動(dòng)畫最終效果是什么弥臼,在給某個(gè)動(dòng)畫屬性賦新值的時(shí)候,它是瞬間被修改的根灯,我們從模型樹中讀取径缅,它的值已經(jīng)是新的值,而在動(dòng)畫過程中的值由呈現(xiàn)樹來保存烙肺。但實(shí)際上 CA 內(nèi)部還有私有的渲染樹 CARender纳猪,渲染當(dāng)前的動(dòng)畫效果,并且是異步的茬高,所以上面兩次提交的動(dòng)畫兆旬,是分別在不同的線程中執(zhí)行的,并且不會(huì)阻塞主線程怎栽。

UIView 是如何禁用隱式動(dòng)畫的

UIView 的內(nèi)容是由 CALayer 呈現(xiàn)的丽猬,但在修改 UIView 屬性的時(shí)候,卻沒有動(dòng)畫效果熏瞄,說明 UIView 在包裝 CALayer 的時(shí)脚祟,對(duì)它做了手腳。

CALayer 屬性的修改的動(dòng)畫被叫做 action强饮,只要實(shí)現(xiàn) CAAction 協(xié)議的類由桌,都可以被作用于 CALayer 的動(dòng)畫。當(dāng) CALayer 的屬性被修改時(shí)邮丰,首先會(huì)調(diào)用 -actionForKey:方法行您,傳遞修改的屬性,接著會(huì)通過4種方式來獲取動(dòng)畫的 action:

  1. CALayer 是否存在代理剪廉,并實(shí)現(xiàn) -actionForlayer:forKey 方法娃循。
  2. 如果代理不存在或者未實(shí)現(xiàn)上述代理方法,會(huì)檢查 actions 字典斗蒋,是否包含所修改屬性的動(dòng)作捌斧。
  3. 如果 actions 字典,不包含當(dāng)前修改的屬性泉沾,會(huì)在繼承體系中查找 style 字典屬性捞蚂。
  4. 最后如果在 style 屬性里也沒法發(fā)現(xiàn),就會(huì)使用默認(rèn)的 -defaultActionForKey:跷究,也就是形成隱式動(dòng)畫的動(dòng)作姓迅。

然而,UIView 禁用隱式動(dòng)畫的方式非常簡(jiǎn)單,它遵循了 CALayerDelegate 并給 方法返回 nil队贱,就不會(huì)有動(dòng)畫效果了色冀。

等等,那如果直接返回 nil柱嫌,那 UIView 不就做不了動(dòng)畫了嗎锋恬?animateWithDuration 這類 block 動(dòng)畫如何實(shí)現(xiàn)呢?比如修改顏色的動(dòng)畫效果:

 UIView.animate(withDuration: 1, delay: 10, options: .curveEaseIn, animations: { 
    self.view.backgroundColor = UIColor.black
}, completion: nil)

雖然傳遞 delay 10 秒编丘,但 block 是瞬間執(zhí)行的与学,只不過動(dòng)畫的效果會(huì)在 10 秒之后才發(fā)生。上述 block 等價(jià)于

UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDelay(10)
UIView.setAnimationDuration(1)
self.view.backgroundColor = UIColor.black
UIView.commitAnimations()

處于 beginAnimationscommitAnimations 之間的屬性修改會(huì)被做標(biāo)記 嘉抓,在 -actionForlayer:forKey 方法中索守,會(huì)為有標(biāo)記的操作返回特定的 CAAction 而不是 nil,UIView 就可以自如的控制是否需要?jiǎng)赢嬓Ч恕?/p>

本文絕大部分內(nèi)容 CALayer 頭文件就有說明抑片,但是如果僅僅看頭文件的注釋卵佛,會(huì)不知所云,稍微了解一些用法敞斋,會(huì)清楚不少截汪。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市植捎,隨后出現(xiàn)的幾起案子衙解,更是在濱河造成了極大的恐慌,老刑警劉巖焰枢,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚓峦,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡济锄,警方通過查閱死者的電腦和手機(jī)暑椰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荐绝,“玉大人一汽,你說我怎么就攤上這事『懿矗” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵沾谓,是天一觀的道長(zhǎng)委造。 經(jīng)常有香客問我,道長(zhǎng)均驶,這世上最難降的妖魔是什么昏兆? 我笑而不...
    開封第一講書人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮妇穴,結(jié)果婚禮上爬虱,老公的妹妹穿的比我還像新娘隶债。我一直安慰自己,他們只是感情好跑筝,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開白布死讹。 她就那樣靜靜地躺著,像睡著了一般曲梗。 火紅的嫁衣襯著肌膚如雪赞警。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,792評(píng)論 1 290
  • 那天虏两,我揣著相機(jī)與錄音愧旦,去河邊找鬼。 笑死定罢,一個(gè)胖子當(dāng)著我的面吹牛笤虫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播祖凫,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼琼蚯,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了蝙场?” 一聲冷哼從身側(cè)響起凌停,我...
    開封第一講書人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎售滤,沒想到半個(gè)月后罚拟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡完箩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年赐俗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弊知。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡阻逮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出秩彤,到底是詐尸還是另有隱情叔扼,我是刑警寧澤,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布漫雷,位于F島的核電站瓜富,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏降盹。R本人自食惡果不足惜与柑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧价捧,春花似錦丑念、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至椎眯,卻和暖如春挠将,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背编整。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工舔稀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人掌测。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓内贮,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親汞斧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子夜郁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348

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

  • 在前面的學(xué)習(xí)中,我們討論了CoreAnimation除了動(dòng)畫外可以做到的任何事情粘勒。但是動(dòng)畫是CoreAni...
    小貓仔閱讀 1,520評(píng)論 0 0
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果竞端,實(shí)現(xiàn)這些動(dòng)畫的過程并不復(fù)雜,今天將帶大家一窺iOS動(dòng)畫全貌庙睡。在這里你可以看...
    F麥子閱讀 5,101評(píng)論 5 13
  • 隱式動(dòng)畫 按照我的意思去做乘陪,而不是我說的统台。 -- 埃德娜,辛普森 我們?cè)诘谝徊糠钟懻摿顺藙?dòng)畫之外啡邑,Core An...
    方圓幾度閱讀 102評(píng)論 0 0
  • Core Animation Core Animation除了動(dòng)畫之外可以做到的任何事情贱勃。但是動(dòng)畫是Core An...
    清風(fēng)沐沐閱讀 641評(píng)論 1 3
  • 本文轉(zhuǎn)載自:http://www.cocoachina.com/ios/20150105/10812.html 為...
    idiot_lin閱讀 407評(píng)論 0 2