教程: CAReplicatorLayer動畫

本文翻譯自:http://www.ios-animations-by-emails.com/posts/2015-march#tutorial

在這個教程中我會用CAReplicatorLayer實(shí)現(xiàn)三種炫酷的動畫效果柠衍,代碼用 Xcode 7/Swift2實(shí)現(xiàn)倒信。

我們首先將重新實(shí)現(xiàn)iOS內(nèi)置音樂應(yīng)用的“volumn bars”效果铅匹,歌曲"Pyramid Song"的右方凿宾。


接下來我們實(shí)現(xiàn)一個自定義的activity indicator,最后我們用一種特別的方式實(shí)現(xiàn) raywenderlich.com的logo滩届。

1. 基本的Replicator動畫

CAReplicatorLayer是一個容器層腐芍,我們向其中增加內(nèi)容差导,然后它對其進(jìn)行復(fù)制。我們放入一個圖形猪勇,它將生成多個圖形设褐。最棒的是我們可以自己定義這些復(fù)制圖形角度偏差以及和上一個圖形之間的透明度、顏色變化等泣刹。這種特性能讓我們創(chuàng)造出炫酷的動畫效果助析。

此教程第一部分我們就來復(fù)制iOS Music app上的這個動畫!


這個動畫的特點(diǎn)是一根紅色的bar上下伸縮椅您,然后旁邊復(fù)制了兩個這樣的動畫外冀,只不過動畫有一些偏移而已。
首先創(chuàng)建一個新的xcode poject掀泳,選擇Single View template雪隧。打開 ViewController.swift
viewDidLoad()中加入:

animation1()

并且在ViewController中加上這個空方法:

func animation1() {

}

現(xiàn)在我們在animation1()中創(chuàng)建我們的replicator layer:

let r = CAReplicatorLayer()
r.bounds = CGRect(x:0.0, y:0.0, width:60.0, height: 60.0)
r.position = view.center
r.backgroundColor = UIColor.lightGrayColor().CGColor
view.layer.addSublayer(r)

我們創(chuàng)建了一個CAReplicatorLayer的實(shí)例员舵,設(shè)置了bounds和position脑沿,為了確定layer的位置,我們暫且設(shè)置layer的背景色為light gray固灵。

啟動程序捅伤,我們會看到我們的layer只是靜靜地待在那:


現(xiàn)在,我們來創(chuàng)建第一個bar巫玻,加入到animation1()中:

let bar = CALayer()
bar.bounds = CGRect(x:0.0, y:0.0, width:8.0, height:40.0)
bar.position = CGPoint(x:10.0, y:75.0)
bar.cornerRadius = 2.0
bar.backgroundColor = UIColor.redColor().CGColor

r.addSubLayer(bar)

這段代碼創(chuàng)建了一個紅色的圓角矩形,設(shè)置它的位置在replicator layer的左邊緣祠汇。啟動程序仍秤,我們會看到:



這個紅色的bar出現(xiàn)在replicator layer的外面,是因?yàn)槲覀儠宐ar進(jìn)行上下位移可很。動畫開始的位置正好是在replicator layer的下面 -- 這就是為什么紅色bar會看起來有那么一點(diǎn)偏移诗力。

接下來我們加入紅色bar的動畫:

let move = CABasicAnimation(keyPath: "position.y")
move.toValue = bar.position.y - 35.0
move.duration = 0.5
move.autoreverses = true
move.repeatCount = Float.infinity

bar.addAnimation(move, forKey: nil)

這樣會讓bar無限的重復(fù)上下位移...雖然很丑陋...但是是個不錯的開始!
下面來見識下replicator的魔力!加入下面這行代碼:

r.instanceCount = 3

這行代碼告訴replicator我們想要三個我們屏幕上的bar的拷貝苇本,包括了最初我們自己創(chuàng)建的那一個袜茧。如果這時候我們啟動程序我們并不會看到任何改變,因?yàn)樗械倪@三個拷貝都在同一個位置同一時間做著同步的動畫瓣窄,我們需要增加一些offset:

r.instanceTransform = CATransform3DMakeTranslation(20.0, 0.0, 0.0)

這樣我們就告訴了replicator layer笛厦,我們應(yīng)用這個transform到所有的拷貝當(dāng)中。我們設(shè)置instanceTransform來對每一份拷貝進(jìn)行20的位置偏移俺夕,當(dāng)我們運(yùn)行程序會看到:


我們最初的紅色bar終于有了兩份克隆并且上下位移著裳凸!最后一步是讓動畫開始時間也有一定的偏移:

r.instanceDelay = 0.33

instanceDelay這個屬性是延遲replicator layer對每個copy的渲染,因此看起來就會有我們想要的有層次的動畫劝贸。

接下來我們還需要兩處改變:

  • 把replicator layer外面的紅色bar給隱藏掉姨谷,加入r.masksToBounds = true;
  • 刪除replicator layer的backgroundColor

最后我們能看到我們想要的結(jié)果:


2. Activity indicator

我們現(xiàn)在來實(shí)現(xiàn)更為復(fù)雜的復(fù)制動畫!在viewDidLoad()中替換animation1()為:

animation2()

接下來一樣映九,提供一個空的方法實(shí)現(xiàn):

func animation2() {

}

這章我們會創(chuàng)建一個activity indicator梦湘,并且動畫比iOS系統(tǒng)自帶的activity更為精細(xì)。
我們從animation2()中加入replicator layer來開始:

let r = CAReplicatorLayer()
r.bounds = CGRect(x:0.0, y:0.0, width:200.0, height:200.0)
r.cornerRadius = 10.0
r.backgroundColor = UIColor(white:0.0, alpha:0.75).CGColor
r.position = view.center

view.layer.addSublayer(r)

和之前的一樣件甥,我們創(chuàng)建了一個帶有背景色的空replicator layer践叠,但這次我們保留這個背景色。
接下來加入一個簡單的layer來畫一個白色的矩形:

let dot = CALayer()
dot.bounds = CGRect(x:0.0, y :0.0, width:14.0, height:14.0)
dot.position = CGPoint(X:100.0, y:40.0)
dot.backgroundColor = UIColor(white:0.8, alpha:1.0).CGColor
dot.borderColor = UIColor(white:1.0, alpha:1.0).CGColor
dot.borderWidth = 1.0
dot.cornerRadius = 2.0

r.addSublayer(dot)

我們創(chuàng)建了一個14*14的圓角矩形嚼蚀,最后我們把它加入到replicator中禁灼,啟動程序我們可以看到:



接下來配置replicator來復(fù)制15個點(diǎn),這15個點(diǎn)以2π/15的角度差來布局:

let nrDots: Int = 15
r.instanceCount = nrDots
let angle = CGFloat(2*M_PI) / CGFloat(nrDots)
r.instanceTransform = CATransform3DMakeRotation(angle, 0.0, 0.0, 1.0)

再次運(yùn)行程序轿曙,能夠看到:



我們可以嘗試性修改nrDots的值為10弄捕、25或者其他值:



現(xiàn)在我們來創(chuàng)建一個1.5秒的scale動畫:
let durition:CFTimeInterval = 1.5
let shrink = CABasicAnimation(keyPath: "transform.scale")
shrink.fromValue = 1.0
shrink.toValue = 0.1
shrink.duration = duration
shrink.repeatCount = Float.infinity

dot.addAnimation(shrink, forKey: nil)

這段代碼讓每個同步謎一樣地縮小消失又出現(xiàn)。导帝。守谓。
下面大家應(yīng)該都知道了,該加一些delay了:

r.instanceDelay = duration/Double(nrDots)

這樣我們的點(diǎn)就開始像在旋轉(zhuǎn)起來了您单,但是第一遍的動畫非常奇怪斋荞,所有點(diǎn)都是先是大的,然后到第二遍才開始正確的動畫虐秦。
解決這個問題我們只需要在animation2()的最后加上這段代碼:

dot.transform = CATransfor3DMakeScale(0.01, 0.01, 0.01)

看起來很棒:



其實(shí)動畫比想象的要簡單是不是平酿,我們可以在這個基礎(chǔ)的activity indicator代碼上添加自己的一些嘗試,便可以創(chuàng)建出更酷的效果悦陋。

3. Follow the leader

最后的動畫叫做 Follow the leader(不會翻譯...)蜈彼,在這個動畫中我們通過path路徑來實(shí)現(xiàn)這個效果。
還是在viewDidLoad()當(dāng)中俺驶,替換方法animation2()為:

animation3()

同上幸逆,先創(chuàng)建個空的方法實(shí)現(xiàn):

func animation3() {

}

這個動畫中,我們需要更多的輔助函數(shù),用PaintCode這個app我們可以快速生成貝賽爾曲線的代碼还绘,這個曲線路徑便是我們需要的動畫path楚昭,加入這個方法到ViewController中:

func rw() -> CGPath {
    let bezierPath = UIBezierPath()     
    bezierPath.moveToPoint(CGPointMake(31.5, 71.5)) 
    bezierPath.addLineToPoint(CGPointMake(31.5, 23.5)) 
    bezierPath.addCurveToPoint(CGPointMake(58.5, 38.5), controlPoint1: CGPointMake(31.5, 23.5), controlPoint2: CGPointMake(62.46, 18.69)) 
    bezierPath.addCurveToPoint(CGPointMake(53.5, 45.5), controlPoint1: CGPointMake(57.5, 43.5), controlPoint2: CGPointMake(53.5, 45.5)) 
    bezierPath.addLineToPoint(CGPointMake(43.5, 48.5)) 
    bezierPath.addLineToPoint(CGPointMake(53.5, 66.5)) 
    bezierPath.addLineToPoint(CGPointMake(62.5, 51.5)) 
    bezierPath.addLineToPoint(CGPointMake(70.5, 66.5)) 
    bezierPath.addLineToPoint(CGPointMake(86.5, 23.5)) 
    bezierPath.addLineToPoint(CGPointMake(86.5, 78.5)) 
    bezierPath.addLineToPoint(CGPointMake(31.5, 78.5)) 
    bezierPath.addLineToPoint(CGPointMake(31.5, 71.5)) 
    bezierPath.closePath()

    var t = CGAffineTransformMakeScale(3.0, 3.0)
    return CGPathCreateCopyByTransformingPath(bezierPath.CGPath, &t)!
}

這個方法創(chuàng)建了一個CGPath,之后我們便會用它來創(chuàng)建關(guān)鍵幀動畫拍顷。
animation()中加入:

let r = CAReplicatorLayer()
r.bounds = view.bounds
r.backgroundColor = UIColor(white:0.0, alpha:0.75).CGColor
r.position = view.center

view.layer.addSublayer(r)

下面來創(chuàng)建我們的第一個layer:

let dot = CALayer()
dot.bounds = CGRect(x:0.0, y:0.0, width:10.0, height:10.0)
dot.backgroundColor = UIColor(white:0.8, alpha:1.0).CGColor
dot.borderColor = UIColor(white:1.0, alpha:1.0).CGColor
dot.borderWidth = 1.0
dot.cornerRadius = 5.0
dot.shouldRasterize = true
dot.rasterizationScale = UIScreen.mainScreen().scale

r.addSublayer(dot)

我們創(chuàng)建了一個小的銀色圓抚太,這時候我們?nèi)绻\(yùn)行程序就會看到這個圓位于屏幕的左上方。
接著就是動畫:

let move = CAKeyframeAnimation(keyPath:"position")
move.path = rw()
move.repeatCount = Float.infinity
move.duration = 4.0
dot.addAnimation(move, forKey: nil)

這個動畫會圍繞著rw()生成的path做位移菇怀,持續(xù)4秒并且永遠(yuǎn)重復(fù)著凭舶。
老樣子,我們加入copy以及delay:

r.instanceCount = 20
r.instanceDelay = 0.1


設(shè)置instanceColormultiplies the original content color by the color you provide(水平有限爱沟,翻譯不出帅霜,反正這屬性挺神奇,可以試試)呼伸,并且和instanceGreenOffset一起能做出更炫酷的效果身冀。

r.instanceColor = UIColor(red:0.0, green:1.0, blue:0.0, alpha:1.0).CGColor
r.instanceGreenOffset = -0.03

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市括享,隨后出現(xiàn)的幾起案子搂根,更是在濱河造成了極大的恐慌,老刑警劉巖铃辖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剩愧,死亡現(xiàn)場離奇詭異,居然都是意外死亡娇斩,警方通過查閱死者的電腦和手機(jī)仁卷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來犬第,“玉大人锦积,你說我怎么就攤上這事∏干ぃ” “怎么了丰介?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鉴分。 經(jīng)常有香客問我哮幢,道長,這世上最難降的妖魔是什么冠场? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任家浇,我火速辦了婚禮,結(jié)果婚禮上碴裙,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好舔株,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布莺琳。 她就那樣靜靜地躺著,像睡著了一般载慈。 火紅的嫁衣襯著肌膚如雪惭等。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天办铡,我揣著相機(jī)與錄音辞做,去河邊找鬼。 笑死寡具,一個胖子當(dāng)著我的面吹牛秤茅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播童叠,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼框喳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了厦坛?” 一聲冷哼從身側(cè)響起五垮,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎杜秸,沒想到半個月后放仗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡撬碟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年诞挨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片小作。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡亭姥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出顾稀,到底是詐尸還是另有隱情达罗,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布静秆,位于F島的核電站粮揉,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏抚笔。R本人自食惡果不足惜扶认,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望殊橙。 院中可真熱鬧辐宾,春花似錦狱从、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至誉察,卻和暖如春与涡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背持偏。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工驼卖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鸿秆。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓酌畜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親谬莹。 傳聞我的和親對象是個殘疾皇子檩奠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

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