iOS核心動畫高級技巧之圖層變換和專用圖層(二)


iOS核心動畫高級技巧之CALayer(一)

iOS核心動畫高級技巧之圖層變換和專用圖層(二)
iOS核心動畫高級技巧之核心動畫(三)
iOS核心動畫高級技巧之性能(四)
iOS核心動畫高級技巧之動畫總結(五)
 
 
 

  仿射變換

  iOS仿射變換是CGAffineTransform,仿射變換的特點是變換后的圖形對邊依然是平行的,它包括 CGAffineTransformMakeRotation(CGFloat angle) / CGAffineTransformMakeScale(CGFloat sx, CGFloat sy) / CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty),直接看代碼

 1 blueView = UIView()  2 blueView.frame = CGRectMake(50, 100, 100, 100)  3 blueView.backgroundColor = UIColor.blueColor()  4 self.view.addSubview(blueView)  5 
 6 yellowView = UIView()  7 yellowView.frame = CGRectMake(50 + 200 / 1.414, 100, 100, 100)//注意yellowView的水平位置,和blueView作對比
 8 yellowView.backgroundColor = UIColor.yellowColor()  9 self.view.addSubview(yellowView) 10 
11 blueView.transform = CGAffineTransformIdentity  //初始化transform
12 blueView.transform = CGAffineTransformMakeScale(0.5, 0.5 )  //縮小0.5倍
13 blueView.transform = CGAffineTransformRotate(blueView.transform, CGFloat(M_PI_4))   //旋轉pi/4
14 blueView.transform = CGAffineTransformTranslate(blueView.transform, 400, 0) //平移400

   這里只需要注意transform的疊加互相之間是有影響的,blueView縮小了0.5倍和旋轉了45°,所以本來應該在水平位置上平移400的最后在45°方向平移了200,所以在水平方向平移的距離大約是200/1.414,和yellowView形成對比.

  3D變換

  3D變換和仿射變換不同,雖然它也是乘以一個二維向量,但是它是4x4的二維向量,而仿射變換是2x3的向量,而且3D變換可以通過直接改變向量的單個的值來設置向量,比如transform.m11 / transform.m44 對應的就是向量上對應位置的值,由於是3維空間的變換,所以有些不同,仿射的旋轉等價於3D變換的Z軸旋轉,它的x,y的組合向量可以使它向傾斜的角度(如45°)旋轉,而平移忽略掉Z軸上的就是一樣的,縮放也是忽略掉Z軸上的就行.而由於是3D變換縮放會使平移縮放對應比例,而x/y/z軸的旋轉都不會使它的方向改變,這是由於矩陣的值表示的范圍廣,不會互相影響.

1 blueLayer.transform = CATransform3DIdentity  //初始化transform
2 blueLayer.transform = CATransform3DMakeScale(0.5, 0.5, 0)  //縮小0.5倍
3 blueLayer.transform = CATransform3DRotate(blueLayer.transform,CGFloat( M_PI_4 ), 0.0,  1.0, 0) //旋轉pi/4
4 blueLayer.transform = CATransform3DTranslate(blueLayer.transform,400, 0, 0)     //平移400

   由於3D變換分成多個方向的,所以沿X或Y方向的旋轉就像縮放了一樣,可以通過設置向量對應的值來修復這個效果,讓它看上去更真實一點,結果它會有一個傾斜角度,有一個投影效果,這樣當你做平移的時候會改變顯示的大小,所以一般不要一起用了,而要讓這個效果有效,需要在初始化transform時就設置m34的值(這個值最好在-1/500.0 到 -1/5000.0之間),放到后面沒有效果,在后面也不能用scale放大縮小,不然會覆蓋這個值.所以這個效果基本是單獨拿出來顯示效果的.

1 var transform = CATransform3DIdentity //初始化transform
2 transform.m34 = -1 / 500.0 //設置m34的值 3 // transform = CATransform3DScale( transform, 0.5, 0.5, 0) //縮小0.5倍,這里不能用
4 transform = CATransform3DRotate(transform,CGFloat( M_PI_4 ), 0.0,  1.0, 0) //旋轉pi/4
5 transform = CATransform3DTranslate(transform,400, 0, 0)     //平移400
6 blueLayer.transform = transform

  當你在投射的方向平移足夠大的距離,它最后的成像就是一個點了,這個點一般是圖層的anchorPoint點,如果是一個圖層的好幾個子圖層都需要這種效果,那么直接設置它的父圖層transform的m34為-1/ 500.0 然后設置它的sublayerTransform屬性,當設置它的子layer的rotote屬性那個子layer就會有對應的投射效果. 如:outLayer.sublayerTransform = outLayer.transform

   如果旋轉180°從背面去看layer,layer會顯示出和layer對稱的的圖片,因為layer是雙面繪制的,但如果有文字就會看起來很混亂並且浪費GPU資源,所以最好能夠禁用它,而layer提供了這個屬性:doubleSided,值為true雙面為false則為單面.

  內外層layer的選擇可以相互疊加和抵消,這個在Z軸上的旋轉是可以的,但是在X/Y上並不是這樣的,是由於它們並不處於同一個3D空間內,同時需要注意的是,如果使用m34這個特殊的向量值做投影,每次先給一個transform初始化為CATransform3DIdentity,然后直接設置m34的值然后做旋轉等,再賦值給layer的transform

  專用圖層

 CAShapeLayer

  CAShapeLayer 是專門用來繪畫形狀的layer,它對比畫圖有很大的優勢,它使用了硬件加速,所以繪圖速度很快,它不需要寄宿圖片所以不會使用太多內存,它也不會和普通圖層一樣被裁剪掉,而且它不會被像素化,最后就不會模糊.你可以設置lineWith(線寬,用點表示單位)/ lineCap(線條結尾的樣子)和lineJoin(線條之間的結合點的樣子),但是只有一次設置的機會.CAShapeLayer還可以單獨設置圓角,下面是代碼和對應的兩個運行效果,前面一個線條的人另一個是3個圓角的直角矩形.

DEMO1:
1
let shapePath = UIBezierPath() 2 shapePath.moveToPoint(CGPointMake(175, 100)) 3 shapePath.addArcWithCenter(CGPointMake(150, 100), radius: 25, startAngle: 0, endAngle:CGFloat( 2 * M_PI ), clockwise: true) 4 shapePath.moveToPoint(CGPointMake(150, 125)) 5 shapePath.addLineToPoint(CGPointMake(150, 175)) 6 shapePath.addLineToPoint(CGPointMake(125, 225)) 7 shapePath.moveToPoint(CGPointMake(150, 175)) 8 shapePath.addLineToPoint(CGPointMake(175, 225)) 9 shapePath.moveToPoint(CGPointMake(100, 150)) 10 shapePath.addLineToPoint(CGPointMake(200, 150)) 11 12 let shapeLayer = CAShapeLayer() 13 shapeLayer.strokeColor = UIColor.redColor().CGColor 14 shapeLayer.fillColor = UIColor.clearColor().CGColor 15 shapeLayer.lineWidth = 5 16 shapeLayer.lineJoin = kCALineJoinRound 17 shapeLayer.lineCap = kCALineCapRound 18 shapeLayer.path = shapePath.CGPath 19 self.view.layer.addSublayer(shapeLayer)
DEMO2:
1
var rect = CGRectMake(50, 50, 100, 100); 2 var radii = CGSizeMake(20, 20); 3 var corners = UIRectCorner.TopRight | UIRectCorner.BottomRight | UIRectCorner.BottomLeft 4 var shapePath = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: radii) 

 

 CATextLayer

   可以在layer中直接用Core Graphics直接寫入文字,這就是UILabel的實現方式,如果直接在圖層上記錄文本將是一件很麻煩的事,iOS提供了CATextLayer來實現layer上顯示文本,它本身使用了Core text ,渲染速度很快.

 1 var textLayer = CATextLayer()
 2 textLayer.frame = CGRectMake(100, 100, 200, 300)
 3 self.view.layer.addSublayer(textLayer)
 4 
 5 //設置它的屬性
 6 textLayer.foregroundColor = UIColor.redColor().CGColor
 7 textLayer.alignmentMode = kCAAlignmentJustified
 8 textLayer.wrapped = true
 9 
10 //它的font是CGFont類型,需要大小字體分開設置
11 var font = UIFont.systemFontOfSize(24)
12 textLayer.font = CGFontCreateWithFontName(font.fontName)
13 textLayer.fontSize = font.pointSize
14 
15 var textStr = "hello kitty hi nohhhh no wo  shi lllll aaaaawo  jiojhello kitty hi nohhhh no wo  shi lllll aaaaawo  jioj"
16 textLayer.string = textStr
17 
18 //它contentScale默認是1,為了讓它以retina的質量來顯示,設置為2
19 textLayer.contentsScale = UIScreen.mainScreen().scale

    這里也可以用NSAttributedString富文本,但是由於swift類型轉換的問題挺麻煩的,不寫demo了.

CATransformLayer

  這個圖層類解決了圖層間的層級關系,如下面這個demo所示:如果是CALayer旋轉就沒有層級,如果是CATransformLayer,它就有了層級

 1 //outLayer = CALayer()
 2 outLayer = CATransformLayer() //如果是上面這個普通的CALayer它如果旋轉就不會有雙層的效果
 3 
 4 
 5 outLayer.frame = CGRectMake(50, 50, 300, 300)
 6 outLayer.backgroundColor = UIColor.grayColor().CGColor
 7 self.view.layer.addSublayer(outLayer)
 8 
 9 var transform = CATransform3DIdentity //初始化transform
10 transform.m34 = -1 / 500.0 //設置m34的值
11 transform = CATransform3DRotate(transform,CGFloat( M_PI_2 ), 0.0,  1.0, 0) //旋轉pi/4
12 outLayer.transform = transform
13 
14 //outLayer.sublayerTransform = transform
15 
16 
17 blueLayer = CALayer()
18 blueLayer.frame = CGRectMake(50, 50, 200, 200)
19 blueLayer.backgroundColor = UIColor.blueColor().CGColor
20 outLayer.addSublayer(blueLayer)
21 
22 
23 var blueLayerTransform = CATransform3DIdentity;
24 blueLayerTransform  = CATransform3DTranslate(blueLayerTransform, 0, 0, 50);
25 blueLayer.transform = blueLayerTransform;
26 
27 redLayer = CALayer()
28 redLayer.frame = CGRectMake(50, 50, 200, 200)
29 redLayer.backgroundColor = UIColor.redColor().CGColor
30 outLayer.addSublayer(redLayer)
31 
32 var fromValue = CATransform3DIdentity
33 fromValue.m34 = -1 / 500.0
34 fromValue = CATransform3DRotate(fromValue, 0, 0, 1, 0)
35 
36 var toValue = CATransform3DIdentity
37 toValue.m34 = -1 / 500.0
38 toValue = CATransform3DRotate(toValue, CGFloat( M_PI ), 0, 1, 0)
39 
40 var basicAnimation = CABasicAnimation(keyPath: "transform")
41 basicAnimation.duration = 1.0
42 basicAnimation.fromValue = NSValue(CATransform3D:fromValue)
43 basicAnimation.toValue = NSValue(CATransform3D:toValue)
44 outLayer.transform = toValue
45 outLayer.addAnimation(basicAnimation, forKey: "transform3D")
View Code

 CAGradientLayer

   CAGradientLayer它主要是可以設置漸變色,通過colors屬性和,startPoint和endPoint設置過渡顏色和位置,這時候設置背景色是沒有用的

1 gradientLayer = CAGradientLayer() 2 gradientLayer.frame = CGRectMake(50, 50, 300, 300) 3 gradientLayer.backgroundColor = UIColor.grayColor().CGColor 4 self.view.layer.addSublayer(gradientLayer) 5 
6 gradientLayer.colors = [UIColor.redColor().CGColor,UIColor.blueColor().CGColor, UIColor.greenColor().CGColor] 7 gradientLayer.startPoint = CGPointMake(0, 0) 8 gradientLayer.endPoint = CGPointMake(1, 1)

    它還有一個locations屬性,可以設置每個漸變色的間距,這個數組的長度需要和colors數組的長度相同,location的值是按endPoint的值來說的,不是是多少及時多少

CAReplicatorLayer

   CAReplicatorLayer可以使用在需要創建多個同樣的layer只是軌跡顏色有規則的變化的時候,它會把它的子圖層有規律的重復展示出來,而可以設置它重復的次數/每次漸變的顏色遞增遞減值/每次transform變換的路徑.

 1 repeatLayer = CAReplicatorLayer()  2 repeatLayer.frame = CGRectMake(50, 50, 300, 300)  3 repeatLayer.backgroundColor = UIColor.grayColor().CGColor  4 self.view.layer.addSublayer(repeatLayer)  5 
 6 var transform = CATransform3DIdentity  7 transform = CATransform3DTranslate(transform, 0, 100, 0);  8 transform = CATransform3DRotate(transform, CGFloat( M_PI / 5.0 ), 0, 0, 1);  9 transform = CATransform3DTranslate(transform, 0, -100, 0); 10 repeatLayer.instanceTransform = transform; 11 
12 repeatLayer.instanceCount = 10
13 
14 repeatLayer.instanceBlueOffset = -0.1
15 repeatLayer.instanceRedOffset = -0.1
16 
17 var layer  = CALayer() 18 layer.frame = CGRect(x: 125, y: 125, width: 50, height: 50) 19 layer.backgroundColor = UIColor.whiteColor().CGColor 20 repeatLayer.addSublayer(layer) 

   它最后的結果就是一圈顏色遞變的正方形,它可以做動畫中一個飛機的路徑等效果.它的一個重要實際用處就是做倒影,因為如果做圖層的復制的話,倒影不可能跟着原layer做實時更新,而CAReplicatorLayer就可以做到.

 1 reflectionLayer = CAReplicatorLayer()
 2 var img = UIImage(named: "3333.jpg")
 3 reflectionLayer.frame = CGRectMake((self.view.bounds.size.width - img!.size.width) / 2 , 100, img!.size.width, img!.size.height * 1.5)
 4 reflectionLayer.backgroundColor = UIColor.grayColor().CGColor
 5 self.view.layer.addSublayer(reflectionLayer)
 6 
 7 var transform = CATransform3DIdentity
 8 transform = CATransform3DScale(transform, 1, -0.5, 1);
 9 transform = CATransform3DTranslate(transform, 0, -img!.size.height * 3 / 4 + 2, 0.0);
10 reflectionLayer.instanceTransform = transform;
11 
12 reflectionLayer.instanceCount = 2
13 
14 var imageLayer  = CALayer()
15 imageLayer.frame = CGRect(x: 0, y: 0, width: img!.size.width, height: img!.size.height)
16 imageLayer.backgroundColor = UIColor.whiteColor().CGColor
17 imageLayer.contents = img!.CGImage
18 //layer.anchorPoint = CGPointMake(0, 0)
19 reflectionLayer.addSublayer(imageLayer)
20 
21 //設置透明度,在外面用個層來設置
22 var gradientLayer = CAGradientLayer()
23 gradientLayer.colors = [UIColor.whiteColor().colorWithAlphaComponent(0.2).CGColor, UIColor.whiteColor().CGColor]
24 gradientLayer.frame = CGRectMake(reflectionLayer.frame.origin.x , reflectionLayer.frame.origin.y + reflectionLayer.frame.size.height / 3.0 * 2, reflectionLayer.frame.size.width, reflectionLayer.frame.size.height / 2)
25 self.view.layer.addSublayer(gradientLayer)
26 
27 
28 //設置文字
29 var textLayer = CATextLayer()
30 textLayer.frame = CGRectMake(80, 50, 200, 300)
31 self.view.layer.addSublayer(textLayer)
32 
33 //設置它的屬性
34 textLayer.foregroundColor = UIColor.redColor().CGColor
35 textLayer.alignmentMode = kCAAlignmentJustified
36 textLayer.wrapped = true
37 
38 //它的font是CGFont類型,需要大小字體分開設置
39 var font = UIFont.systemFontOfSize(24)
40 textLayer.font = CGFontCreateWithFontName(font.fontName)
41 textLayer.fontSize = font.pointSize
42 
43 var textStr = "What a fuck!"
44 textLayer.string = textStr
45 
46 //它contentScale默認是1,為了讓它以retina的質量來顯示,設置為2
47 textLayer.contentsScale = UIScreen.mainScreen().scale
48 
49 imageLayer.addSublayer(textLayer)
50 
51 
52 var basicAnimation = CABasicAnimation(keyPath: "position.y")
53 basicAnimation.duration = 2.0
54 basicAnimation.fromValue =  Float( textLayer.position.y  )
55 var toValue:Float = Float( textLayer.position.y  + 100.0)
56 basicAnimation.toValue = NSNumber(float: toValue)
57 basicAnimation.removedOnCompletion = true
58 basicAnimation.fillMode = kCAFillModeForwards
59 textLayer.addAnimation(basicAnimation, forKey: nil)
60 
61 // textLayer.frame.origin.y = CGFloat( toValue)
62 textLayer.position = CGPointMake(textLayer.position.x, textLayer.position.y  + 100.0)
View Code

 CAScrollLayer 

  CAScrollLayer和UIScrollView類似,它和CALayer相比多了個scrollPoint的方法,如果要用這個方法可以使用CAScrollLayer

1 NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: NSSelectorFromString("setPosition"), userInfo: nil, repeats: false) 2 
3 func setPosition () { 4     self.scrollLayer.scrollToPoint(CGPointMake(0, 100)) 5 }

 CATiledLayer

  CATiledLayer的可以做到圖片/PDF等的分割顯示,如果一個一張圖片分辨率超過2048*2048(因平台不同),超過了OpenGL最大紋理尺寸,所以會有性能問題,一個PDF一般也比較大,所以容易出現性能問題(后面會單獨寫一個demo)

 CAEmitterLayer

  CAEmitterLayer能模仿粒子反射,如果火焰等,能控制粒子顏色/放射的速率,透明度,方向,個數等.

 1 emitterLayer = CAEmitterLayer()  2 emitterLayer.frame = CGRectMake(100 , 100, 200, 200)  3 emitterLayer.backgroundColor = UIColor.grayColor().CGColor  4 self.view.layer.addSublayer(emitterLayer)  5 
 6 emitterLayer.renderMode = kCAEmitterLayerAdditive  7 emitterLayer.emitterPosition = CGPointMake(emitterLayer.frame.size.width / 2, emitterLayer.frame.size.height / 2)  8 
 9 var cell = CAEmitterCell() 10 cell.contents = UIImage(named: "lizi.png")?.CGImage 11 cell.birthRate = 10 //粒子出現的速率
12 cell.lifetime = 4.0 //聲明周期,秒
13 cell.emissionRange = 2 //發射的方向
14 
15 cell.color = UIColor(red: 1, green: 1, blue: 0.5, alpha: 1).CGColor //粒子的顏色
16 cell.alphaSpeed = -0.4 //透明度改變速率
17 cell.velocity = 50//粒子運動速度
18 cell.velocityRange = 100//粒子速度范圍,約束速度
19 
20 emitterLayer.emitterCells = [cell]

 CAEAGLLayer

   它是一個提供用OpenGL ES來繪圖的layer,它可以預先假設要繪制的類型,快速繪制,它可以配合GLKit中的CLKView使用,具體demo專門寫.

AVFoundation

   它是foundation框架里的,但是和layer的使用是一致的,demo如下

 1 var urlStr = NSBundle.mainBundle().pathForResource("1.mp4", ofType: nil)  2 var url = NSURL(fileURLWithPath: urlStr!)  3 var player = AVPlayer(URL: url)  4 
 5 var playLayer = AVPlayerLayer(player: player)  6 playLayer.frame = CGRectMake(0, 0,400, 300)  7 playLayer.backgroundColor = UIColor.grayColor().CGColor  8 self.view.layer.addSublayer(playLayer)  9 
10 player.play()

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM