上一篇文章經過兩個動畫示例帶你們瞭解和認識了CALayer動畫,包括如何使用CAShapeLayer、CABasicAnimation、CAAnimationGroup等。在這篇文章中,依然會經過兩個示例向你們講解更多CALayer動畫的知識。swift
老規矩,先讓咱們看看最終要實現的動畫效果:app
常常聽音樂的人對第一個動畫效果確定有會以爲很眼熟,相似播放音樂時音頻高低起伏的動畫,這種動畫在應用中常被用做標識正在播放音樂或廣播。第二個動畫依然是一個等待加載的動畫,在個人印象中確定是有應用使用過,具體的已經記不清了。下面就讓咱們來實現這兩個動畫吧。動畫
新建一個項目,名爲ReplicatorAnimation,打開Main.storyboard
,添加一個UIView,顏色位置按你們喜愛設定:spa
添加該UIView在ViewController.swift
中的Outlet:.net
接下來咱們在ViewController.swift
中添加一個方法firstReplicatorAnimation()
,在該方法中編寫以下代碼:code
[cpp] view plaincopyorm
let replicatorLayer = CAReplicatorLayer() ip
replicatorLayer.bounds = CGRect(x: replicatorAnimationView.frame.origin.x, y: replicatorAnimationView.frame.origin.y, width: replicatorAnimationView.frame.size.width, height: replicatorAnimationView.frame.size.height) ci
replicatorLayer.anchorPoint = CGPoint(x: 0, y: 0) get
replicatorLayer.backgroundColor = UIColor.lightGrayColor().CGColor
replicatorAnimationView.layer.addSublayer(replicatorLayer)
這裏出現的CAReplicatorLayer是一個新面孔,它也是CALayer的子類,正如它的名稱同樣,CAReplicatorLayer能夠對它本身的子Layer進行復制操做。建立了CAReplicatorLayer實例後,設置了它的尺寸大小、位置、錨點位置、背景色,而且將它添加到了replicatorAnimationView
的Layer中:
這裏要囉嗦幾句,Layer的默認錨點座標是(0.5, 0.5),也就是Layer的中心點位置,而Layer的position
又是根據錨點計算的,因此若是你設置Layer的position
屬性爲(10, 10),就至關於設置了Layer的中心位置爲(10, 10),並非你指望的左上角位置。因此若是Layer想使用它父視圖的座標位置,就須要將錨點位置設置爲(0, 0),這樣一來Layer的position
屬性標識的就是Layer左上角的位置:
而後咱們繼續在firstReplicatorAnimation()
方法中添加代碼:
[cpp] view plaincopy
let rectangle = CALayer()
rectangle.bounds = CGRect(x: 0, y: 0, width: 30, height: 90)
rectangle.anchorPoint = CGPoint(x: 0, y: 0)
rectangle.position = CGPoint(x: replicatorAnimationView.frame.origin.x + 10, y: replicatorAnimationView.frame.origin.y + 110)
rectangle.cornerRadius = 2
rectangle.backgroundColor = UIColor.whiteColor().CGColor
replicatorLayer.addSublayer(rectangle)
經過上面的代碼,再次建立了一個Layer,此次使用的是CALayer,由於咱們只須要一個很普通的Layer,爲其設置位置、尺寸、背景色、圓角屬性,而後添加在replicatorLayer
中:
動畫的主體之一已經繪製好了,下面咱們讓它動起來。在上述代碼後面,接着添加以下代碼:
[cpp] view plaincopy
let moveRectangle = CABasicAnimation(keyPath: "position.y")
moveRectangle.toValue = rectangle.position.y - 70
moveRectangle.duration = 0.7
moveRectangle.autoreverses = true
moveRectangle.repeatCount = HUGE
rectangle.addAnimation(moveRectangle, forKey: nil)
首先咱們建立了按Y軸移動的動畫實例,而後設置了移動的目標位置,動畫持續時間,重複次數設置爲無限大。這裏有一個屬性你們可能比較陌生,那就是autoreverses
,這個屬性爲Bool類型,設置爲true時,開啓自動反向執行動畫,好比示例中的白色長方形的移動動畫爲向上移動50個像素,如過autoreverses
設置爲false,那麼動畫結束後,會根據重複次數,白色長方形從新回到初始位置,繼續向上移動,若是autoreverses
設置爲true,則當動畫結束後,白色長方形會繼續向下移動至初始位置,而後再開始第二次的向上移動動畫。
編譯運行看看效果:
至此,你們應該也已經看出來了,這個白色的長方形就是動畫中第一個上下移動的白色長方形,那麼後兩個如何建立呢?還須要再寫兩遍上面的代碼嗎?請你們在下面的文章中尋找。
在上述代碼下面再添加一行代碼:
[cpp] view plaincopy
replicatorLayer.instanceCount = 3
顯而易見,這是CAReplicatorLayer的能力了,這行代碼的意思是將replicatorLayer
的子Layer複製3份,複製Layer與原Layer的大小、位置、顏色、Layer上的動畫等等全部屬性都如出一轍,因此這時編譯運行代碼咱們看不到任何不一樣的效果,由於三個白色長方形是重合在一塊兒的,因此咱們須要設置每一個白色長方形的間隔:
[cpp] view plaincopy
replicatorLayer.instanceTransform = CATransform3DMakeTranslation(40, 0, 0)
這行代碼涉及到CAReplicatorLayer的另外一個屬性instanceTransform
,它的做用是設置每一個子Layer如何變化。CATransform3DMakeTranslation
這個類的含義是使Layer根據X、Y、Z軸進行平移。如今再編譯運行看看效果如何:
如今三個白色長方形的運動軌跡和時刻都是一直的,這顯然不是咱們想要的結果,咱們須要三個白色長方形有上下起伏的視覺效果,因此咱們繼續添加一行代碼:
[cpp] view plaincopy
replicatorLayer.instanceDelay = 0.3
instanceDelay
這個屬性使CAReplicatorLayer中的每一個子Layer的動畫起始時間逐個遞增。這裏咱們設置爲0.3秒,也就是第一個長方形先執行動畫,過0.3秒後第二個開始執行動畫,再過0.3秒後第三個開始執行動畫。咱們編譯運行看看效果:
顯然咱們只想顯示replicatorLayer
區域裏的內容,咱們並不想看到超出它邊界的內容,因此咱們再添加一行代碼:
[cpp] view plaincopy
replicatorLayer.masksToBounds = true
masksToBounds
是CALayer的屬性,做用是將Layer視爲一個遮罩,只顯示遮罩區域內的內容。最後咱們回到初始化replicatorLayer
的地方,找到這行代碼replicatorLayer.backgroundColor = UIColor.lightGrayColor().CGColor
,將replicatorLayer
的背景色改成無色replicatorLayer.backgroundColor = UIColor.clearColor().CGColor
。再次編譯運行看看最終效果:
CAReplicatorLayer的功能是很強大的,這一節將經過另外一個加載動畫的實例向你們介紹它的其餘特性。
首先打開Main.storyboard
,拖進一個新的UIView,位置顏色隨你們喜愛:
隨後添加該UIView在ViewController.swift
中的Outlet activityIndicatorView
:
而後在ViewController.swift
中添加一個方法activityIndicatorAnimation
,和上一個動畫示例同樣,咱們先建立一個CAReplicatorLayer:
[cpp] view plaincopy
let replicatorLayer = CAReplicatorLayer()
replicatorLayer.bounds = CGRect(x: 0, y: 0, width: activityIndicatorView.frame.size.width, height: activityIndicatorView.frame.size.height)
replicatorLayer.position = CGPoint(x: activityIndicatorView.frame.size.width/2, y: activityIndicatorView.frame.size.height/2)
replicatorLayer.backgroundColor = UIColor.lightGrayColor().CGColor
activityIndicatorView.layer.addSublayer(replicatorLayer)
上述代碼和上個示例中的差很少,惟一不一樣的就是replicatorLayer
的錨點使用的是默認值,即錨點就是中點,position
屬性表明亦是中點,因此將position
屬性設置爲父視圖的中點便可。這裏意在讓你們多多理解CALayer中anchorPoint
與position
屬性。接下來添加以下代碼:
[cpp] view plaincopy
let circle = CALayer()
circle.bounds = CGRect(x: 0, y: 0, width: 15, height: 15)
circle.position = CGPoint(x: activityIndicatorView.frame.size.width/2, y: activityIndicatorView.frame.size.height/2 - 55)
circle.cornerRadius = 7.5
circle.backgroundColor = UIColor.whiteColor().CGColor
replicatorLayer.addSublayer(circle)
上述代碼的目的是用CALayer建立一個圓形,其實CALayer建立出的形狀默認是矩形,可是把四個角的弧度設置爲邊寬的一半,矩形就變成了圓形。將這個圓形的位置設置在父Layer的中間靠上位置,背景色設置爲白色。此時該圓形就是文章開頭效果圖中第二個動畫裏的主體了:
不過在動畫中咱們看到有許多個小圓形組成一個大圓,若是重複上面的代碼,一個一個設置位置,那絕對是使人髮指的行爲,好在咱們有CAReplicatorLayer幫助咱們實現,下面就來看看如何使用CAReplicatorLayer複製子Layer,並讓子Layer造成一個圓形。讓咱們接着添加以下代碼:
[cpp] view plaincopy
replicatorLayer.instanceCount = 15
let angle = CGFloat(2 * M_PI) / CGFloat(15)
replicatorLayer.instanceTransform = CATransform3DMakeRotation(angle, 0, 0, 1)
上述的代碼中,首先對子Layer,也就是白色圓形複製了15份。而後將360°除以15份,算出每個圓形針對它前一個圓形應該偏移的角度。最後咱們用到了CATransform3DMakeRotation
,它一樣是CATransform3D
的一個結構,含義是使Layer在X、Y、Z軸根據給定的角度旋轉。這樣咱們複製的15份圓形就會按照咱們計算的角度排列,並造成一個大圓:
接下來讓咱們分析一下這個動畫,總體看上去感受像一顆流星拖着尾巴在不停的轉圈,但細看每個小圓點,實際上是在不停的進行放大縮小的動畫,只不過每一個小圓點的動畫對於它前一個小圓點的動畫有必定的延遲。因此首先咱們須要實現小圓點放大縮小的動畫,在上述代碼後面接着添加以下代碼:
[cpp] view plaincopy
let scale = CABasicAnimation(keyPath: "transform.scale")
scale.fromValue = 1
scale.toValue = 0.1
scale.duration = 1
scale.repeatCount = HUGE
circle.addAnimation(scale, forKey: nil)
首先建立一個按比例縮放類型的動畫,設置起始比例爲1,也就是當前大小。再設置但願縮放到的比例爲0.1。動畫持續時間爲1秒,重複無限次。最後將該動畫添加在小圓點中。編譯運行看看效果:
目前每一個小圓點是同時執行動畫,咱們須要設置小圓點的動畫延遲時間,接着添加以下代碼:
[cpp] view plaincopy
replicatorLayer.instanceDelay = 1/15
這裏爲何是1/15呢,由於整個動畫的時間是由每一個小圓點的動畫時間決定的,這裏也就是1秒,全部小圓點的延遲時間加起來要等於整個動畫的持續時間,因此這裏就是用1秒除以小圓點的數量15。編譯運行看看效果:
從效果圖中能夠看到,剛開始的動畫不是很天然,那是由於小圓點的初始比例是1,因此一開始會先看到小圓點,而後纔會慢慢開始正常的動畫。這個很好解決,咱們讓小圓點的初始比例爲0.1,也就是剛開始看不到小圓點,這樣就能夠避免這個狀況了,咱們接着加一行代碼:
[cpp] view plaincopy
circle.transform = CATransform3DMakeScale(0.01, 0.01, 0.01)
同時將replicatorLayer
的背景色改成無色,再次編譯運行看看效果:
展示在咱們眼前的是一個完美的加載動畫。