iOS核心動畫基礎 CALayer 圖層變換 專用圖層

本文我們介紹一下IOS開發UI中的核心動畫基礎知識,本文主要內容是講CALayer動畫框架,圖層變換,專用圖層等。CALayer包含在QuartzCore框架中,這是一個跨平台的框架,既可以用在iOS中又可以用在Mac OS X中。

在iOS中CALayer的設計主要是了爲了內容展示和動畫操作,CALayer本身並不包含在UIKit中,它不能回應事件。由于CALayer在設計之初就考慮它的動畫操作功能,CALayer很多屬性在修改時都能形成動畫效果,這種屬性稱爲“隱式動畫屬性”。但是對于UIView的根圖層而言屬性的修改並不形成動畫效果,因爲很多情況下根圖層更多的充當容器的做用,如果它的屬性變動形成動畫效果會直接影響子圖層。
UIView和CALayer的關系


  在iOS中一個UIView對應著一個CALayer,視圖的職責就是創建並管理這個圖層,以確保當子視圖在層級關系中添加或者被移除的時候,他們關聯的圖層也同樣對應在層級關系樹當中有相同的操作.實際上這些背後關聯的圖層才是真正用來在螢幕上顯示和做動畫,UIView僅僅是對它的一個封裝,提供了一些iOS類似于處理觸摸的具體功能,以及Core Animation底層方法的高級接口。(CALayer並不能回應事件,它提供了幾個能判斷一個觸點時候再圖層的範圍之內)
  CALayer存在的意義


  之所以要提供CALayer和UIView這兩個平行層級呢,一方面這樣可以做到職責分離,可以避免很多重複的代碼,另一方面由于iOS和Mac OS的界面其實沒多大差別的,但是由于iOS的多點觸摸的用戶界面和Mac基于滑鼠鍵盤有著本質區別,所以提供一個公用的CALayer來提供界面,分別提供UIView和NSView來提供事件
  CALayer的使用
  平時我們是這樣使用UIView的:

1 let blueView = UIView(frame: CGRectMake(100, 100, 100, 100))
2 blueView.backgroundColor = UIColor.blueColor()
3 self.view.addSubview(blueView)


  而我們可以這樣使用CALayer,你可以直接用下面這段話直接替換掉上面的代碼,程序在外觀上不會有任何區別

1 let blueLayer = CALayer()
2 blueLayer.frame = CGRectMake(100, 100, 100, 100)
3 blueLayer.backgroundColor = UIColor.blueColor().CGColor
4 self.view.layer.addSublayer(blueLayer)


  CALayer內容(contents)相關屬性

contents屬性
  layer有一個contents屬性,它需要傳入一個id(AnyObject!)類型,這是由于它在iOS平台需要CGImage而Mac需要NSImage,在OC中你需要用id類型強轉一下,在Swift中你只需要直接賦一個CGImage就可以了,因爲任何一個Class類型的對象都能賦值給AnyObject,如果你傳入其它對象,程序不會報錯,只是圖片不會顯示出來,UIImageView之所以能顯示圖片內部也是使用了這個contents屬性的緣故
contentGravity屬性
  contentGravity屬性對應于view的contentMode屬性,可以控制layer怎樣對應和拉伸,雖然它的值是字符串,但是swift幫它提供了常量字符串把每個字符串對應了起來
contentsScale屬性
  contentsScale屬性和UIView中的contentScaleFactor是對應的,它決定了一個圖片和視圖的比例,即螢幕一個點顯示幾個像素,這是iOS設備做螢幕適配的原理,一個UIImage是包含scale,direction等信息,而轉化成CGImage會丟失這些信息,自己可以通過contentsScale屬性把image.scale設置給它.
maskToBounds屬性
  maskToBounds屬性對應于CALayer的masksToBounds屬性,如果設置爲true,外部就裁剪了
contentsRect屬性
  contentsRect屬性允許我們在圖層裏顯示圖片的一部分,這個圖片的裁剪區域就是這個屬性,它是一個CGRect,利用它你可以做圖片拼合(即把一套圖片集合在成一張圖片,再對這個圖片裁剪處理了再使用),這樣在記憶體使用/載入時間/渲染效能等方面都有優勢,它的值是按比例的,最大是1.
contentsCenter屬性
  contentsCenter屬性對應著UIImage的resizableImageWithCapInsets,它的值是一個CGRect,它代表的放大的區域,它的效果是黨contentScale放大的時候,只放大contentsCenter區域,其它區域壓縮
  iOS繪圖


  CGImage並不是唯一可以賦值給contents屬性的,也可以使用Core Graphics繪制寄宿圖給它,如果你實現了drawRect方法,然後如果你調用setNeedsDisplay或者外觀屬性被改變時,它就會自動調用drawRect自動重繪,雖然drawRet是一個UIView方法,但是其實都是底層都是CALayer重繪保存了圖片,如果你不需要自定義繪制就不要寫一個空的drawRect方法,它很消耗cpu和記憶體資源
CALayer有一個可選的delegate屬性,如果設置了delegate,並主動調用了layer的displey方法(注意和drawRect不同這個重繪時機是開發者自己控制的,也可以調用setNeedsDisplay方法給系統自己找時機調用),它會調用displayLayer(layer:CALayer!)方法,在這裏是設置contents屬性的最後機會了,如果你沒有實現這個方法,它會嘗試去調用下面這個方法:drawLayer(layer:CALayer!,inContext ctx:CGContext!),如果你實現了displayLayer方法,下面這個方法就不會調用了,drawLayer這個方法裏你可以做繪圖

override func drawLayer(layer: CALayer!, inContext ctx: CGContext!) {
  CGContextSetLineWidth(ctx, 10.0)
  CGContextSetStrokeColorWithColor(ctx, UIColor.redColor().CGColor);
  CGContextStrokeEllipseInRect(ctx, layer.bounds)d060557943
}
override func displayLayer(layer: CALayer!) {
  layer.contents = UIImage(named: "11.png")?.CGImage
}


   由于一個UIView它會把它對應的CALayer的delegate設置爲它自己,所以你不能再設置其它的layer的delegate爲它,在UIView中都用drawRect方法,而delegate的使用只能單獨的使用一個層.
  圖層幾何學
UIView的frame/bounds/center對應CALayer的frame/bounds/position,center和position是對應父圖層的anchorPoint的所在位置,UIView的frame/bounds/center僅僅是存取方法,操縱UIView的這幾個屬性其實是改變CALayer對應的這幾個屬性.而CALayer的frame屬性又是個計算屬性,它是根據bounds/position/transform三個屬性計算出來的,而你改變frame的值也可能影響到其中的值,如果你做旋轉和縮放後frame和bounds可能不再一致了,bounds就是寬高,而frame還要計算旋轉後x和y軸占的空間,如下圖
  CALayer通過anchorPoint(錨點)和center(position)對齊來控制UIView的位置,錨點是相對UIView的一個位置,而center就是一個點,由于anchorPoint屬性對UIView是屏蔽的,而anchorPoint默認值又是{0.5,0.5},所以這個屬性才叫center.而UIView和CALayertransform旋轉也是圍繞這anchorPoint旋轉的,這時候如果是一個圓周運動(比如說時鍾旋轉)就需要設置錨點的值,讓它正常旋轉.如下圖
在CALayer和UIView都有一套可以把它相對于當前父圖層的位置轉換成相對其它圖層(或view)的位置,Mac OS和iOS的坐標系統是相反的,iOS左上Mac OC左下,你可以用layer的geometryFlipped屬性來適配,它可以翻轉坐標系.layer的zPosition屬性是設置它垂直坐標軸的位置的,默認都是0,所以你只要設置爲1,就會顯示在其它層的上面
  可以通過相對坐標轉換判斷點擊的點是否在一個layer或view上,代碼:

 var point = (touches as NSSet).anyObject()?.locationInView(self.view)
point = blueLayer.convertPoint(point!, fromLayer: self.view.layer)
if blueLayer.containsPoint(point!) {
  println("touch in blue")
  
  let yellowPoint = yellowLayer.convertPoint(point!, fromLayer: blueLayer)
  if yellowLayer.containsPoint(yellowPoint) {
    println("touch in yellow")
  }
  
  let redPoint = redLayer.convertPoint(point!, fromLayer: blueLayer)
  if redLayer.containsPoint(redPoint) {
    println("touch in red")
  }
}


  hitTest可以獲取你接觸的那個圖層:

let point = (touches as NSSet).anyObject()?.locationInView(self.view)
let layer = self.view.layer.hitTest(point!)
if layer == blueLayer {
  println("touch in blue")
}
if layer == yellowLayer {
  println("touch in yellow")
}
if layer == redLayer {
  println("touch in red")
}


  UIView可以通過autoresizingMask和constraints等屬性做到自適應螢幕旋轉,CaLayer也有對應的layoutManager屬性和CAConstraintLayoutManager類,但是只能在Mac OS上使用,iOS上還不支持,如果你想使用這個特性你就不能單獨使用layer,但是如果你想調整layer的大小還是可以通過設置layer的delegate,然後實現代理方法layoutSublayersOfLayer直接修改大小顔色之類,它也需要調用setNeedsLayout方法,它和UIView對應的layoutSubviews是一樣的.
  視覺效果
圓角
  layer的cornerRadius屬性可以設置圓角曲率,如果曲率大小爲邊長的一半,圓角會內切于這條邊,如果是個正方形最後的結果就是個圓形,如果是裁剪子視圖也是直接按圓內裁剪
邊框
  layer的borderColor設置邊框顔色,它是CGColorRef,borderWidth設置邊框寬度,值得注意的是邊框寬度占用的是layer的frame的寬度,它並不會在layer外面加一層邊框而是在內部生成.而layer會被子layer覆蓋但邊框不會被覆蓋,並且邊框只是顯示用的,它不會幹擾觸摸和事件,有沒有邊框都是一樣的.
陰影
  陰影至少需要shadowColor/shadowOffset/shadowOpacity三個屬性才能起作用,shadowOffset的值是CGSize類型,兩個正值是朝右下角.還有一個屬性shadowRadius,它控制陰影的邊界模糊程度,默認值是3,值爲0則不模糊,值越大越模糊,模糊的結果是CGSize放心顔色重,其它幾個方向也有對應的陰影,會有一個層次感.
因爲陰影是在layer外部的,所以如果要裁剪超出layer的子視圖則需要使用maskToBounds屬性,而這時陰影也會被裁剪掉,所以當maskToBounds和陰影共存時需要特殊處理下:

blueLayer = CALayer()
blueLayer.frame = CGRectMake(50, 100, 300, 300)
blueLayer.backgroundColor = UIColor.blueColor().CGColor
blueLayer.cornerRadius = blueLayer.bounds.size.width / 2.0
blueLayer.borderColor = UIColor.purpleColor().CGColor
blueLayer.borderWidth = 10.0
blueLayer.masksToBounds = true
let shadowLayer = CALayer()
shadowLayer.frame = blueLayer.frame
shadowLayer.cornerRadius = blueLayer.cornerRadius
shadowLayer.shadowColor = UIColor.redColor().CGColor
shadowLayer.shadowOffset = CGSizeMake(23 , 23.0)
shadowLayer.shadowOpacity = 1
shadowLayer.shadowRadius = 60
shadowLayer.backgroundColor = UIColor.redColor().CGColor
self.view.layer.addSublayer(shadowLayer)
self.view.layer.addSublayer(blueLayer)


  需要注意的是陰影層需要有背景色,不然它的陰影顯示不出來
  shadowPath屬性可以設置陰影的形狀,注意swift中的CGMutablePath並不會增加引用計數,你不需要relase它也沒有方法可以提供給你release

let circlePath = CGPathCreateMutable()
CGPathAddEllipseInRect(circlePath, nil, self.blueLayer.bounds)
shadowLayer.shadowPath = circlePath


  當然你也可以使用UIBezierPath來設置更複雜的形狀給shadowPath

let path1 = UIBezierPath(roundedRect: CGRectMake(-75, -75, 200, 200), cornerRadius: 30).CGPath
let path2 = UIBezierPath(arcCenter: CGPointMake(25, 40), radius: 100, startAngle: 0, endAngle: 3.14159265, clockwise: true).CGPath
shadowLayer.shadowPath = path1
shadowLayer.shadowPath = path2


  圖片蒙板
  layer的mask屬性可以設置一個layer給他,這個layer的contents應該是一個32位有alpha通道的png圖片,你可以設置一個不規則的圖片其它部分爲透明,這樣就對layer設置了一個蒙板,蒙板的顔色不重要,輪廓比較重要,最後被設置了蒙板的layer它只會顯示mask蒙板形狀的內容.
let maskLayer = CALayer()
maskLayer.frame = CGRectMake(0, 0, 100, 100)
maskLayer.contents = UIImage(named: "111.png")?.CGImage
blueLayer.mask = maskLayer
  拉伸
  如果設置的圖片不需要拉伸有很多好處,即不需要拉伸圖片,又能合理的使用記憶體和cpu,但是很多時候一張圖片要多個位置使用,所以需要拉伸,iOS跟我們提供了3中拉伸方式kCAFilterLinear/kCAFilterNearest/kCAFilterTrilinear,設置拉伸方式只需要跟layer的這兩個屬性賦對應的拉伸方式就可以:minification(縮小圖片)和magnification(放大圖片),這個屬性默認是kCAFilterLinear,它和kCAFilterTrilinear類似,他們都是線性的,意思就是它會取兩個值的過度色,讓對應點能順滑的過渡,如果圖片有漸變色和斜線比較多就需要用這個默認的,如果圖片主要是單色而且主要是垂直方向的顔色,那麽就需要kCAFilterNearest,它是暴力的直接取周圍的顔色,那樣又不會失真,也不會太消耗cpu
  組透明
  iOS8默認就是組透明,在應用透明度之前,它會把子圖層和它整合成一個整體的圖片,那樣就沒有透明度混合的問題了,目前沒有測試出透明度出問題的情況,如果有可以設置layer的shouldRasterize的值爲YES
仿射變換
  iOS仿射變換是CGAffineTransform,仿射變換的特點是變換後的圖形對邊依然是平行的,它包括 CGAffineTransformMakeRotation(CGFloat angle) / CGAffineTransformMakeScale(CGFloat sx, CGFloat sy) / CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty),直接看代碼

blueView = UIView()
blueView.frame = CGRectMake(50, 100, 100, 100)
blueView.backgroundColor = UIColor.blueColor()
self.view.addSubview(blueView)
yellowView = UIView()
yellowView.frame = CGRectMake(50 + 200 / 1.414, 100, 100, 100)//注意yellowView的水平位置,和blueView作對比
yellowView.backgroundColor = UIColor.yellowColor()
self.view.addSubview(yellowView)
blueView.transform = CGAffineTransformIdentity //初始化transform
blueView.transform = CGAffineTransformMakeScale(0.5, 0.5 ) //縮小0.5倍
blueView.transform = CGAffineTransformRotate(blueView.transform, CGFloat(M_PI_4))  //旋轉pi/4
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軸的旋轉都不會使它的方向改變,這是由于矩陣的值表示的範圍廣,不會互相影響.

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


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

var transform = CATransform3DIdentity //初始化transform
transform.m34 = -1 / 500.0 //設置m34的值
// transform = CATransform3DScale( transform, 0.5, 0.5, 0) //縮小0.5倍,這裏不能用
transform = CATransform3DRotate(transform,CGFloat( M_PI_4 ), 0.0, 1.0, 0) //旋轉pi/4
transform = CATransform3DTranslate(transform,400, 0, 0)   //平移400
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:
let shapePath = UIBezierPath()
shapePath.moveToPoint(CGPointMake(175, 100))
shapePath.addArcWithCenter(CGPointMake(150, 100), radius: 25, startAngle: 0, endAngle:CGFloat( 2 * M_PI ), clockwise: true)
shapePath.moveToPoint(CGPointMake(150, 125))
shapePath.addLineToPoint(CGPointMake(150, 175))
shapePath.addLineToPoint(CGPointMake(125, 225))
shapePath.moveToPoint(CGPointMake(150, 175))
shapePath.addLineToPoint(CGPointMake(175, 225))
shapePath.moveToPoint(CGPointMake(100, 150))
shapePath.addLineToPoint(CGPointMake(200, 150))
let shapeLayer = CAShapeLayer()
shapeLayer.strokeColor = UIColor.redColor().CGColor
shapeLayer.fillColor = UIColor.clearColor().CGColor
shapeLayer.lineWidth = 5
shapeLayer.lineJoin = kCALineJoinRound
shapeLayer.lineCap = kCALineCapRound
shapeLayer.path = shapePath.CGPath
self.view.layer.addSublayer(shapeLayer)
DEMO2:
var rect = CGRectMake(50, 50, 100, 100);
var radii = CGSizeMake(20, 20);
var corners = UIRectCorner.TopRight | UIRectCorner.BottomRight | UIRectCorner.BottomLeft
var shapePath = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: radii)


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

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


   這裏也可以用NSAttributedString富文本,但是由于swift類型轉換的問題挺麻煩的,不寫demo了.
CATransformLayer
  這個圖層類解決了圖層間的層級關系,如下面這個demo所示:如果是CALayer旋轉就沒有層級,如果是CATransformLayer,它就有了層級

//outLayer = CALayer()
outLayer = CATransformLayer() //如果是上面這個普通的CALayer它如果旋轉就不會有雙層的效果
outLayer.frame = CGRectMake(50, 50, 300, 300)
outLayer.backgroundColor = UIColor.grayColor().CGColor
self.view.layer.addSublayer(outLayer)
var transform = CATransform3DIdentity //初始化transform
transform.m34 = -1 / 500.0 //設置m34的值
transform = CATransform3DRotate(transform,CGFloat( M_PI_2 ), 0.0, 1.0, 0) //旋轉pi/4
outLayer.transform = transform
//outLayer.sublayerTransform = transform
blueLayer = CALayer()
blueLayer.frame = CGRectMake(50, 50, 200, 200)
blueLayer.backgroundColor = UIColor.blueColor().CGColor
outLayer.addSublayer(blueLayer)
var blueLayerTransform = CATransform3DIdentity;
blueLayerTransform = CATransform3DTranslate(blueLayerTransform, 0, 0, 50);
blueLayer.transform = blueLayerTransform;
redLayer = CALayer()
redLayer.frame = CGRectMake(50, 50, 200, 200)
redLayer.backgroundColor = UIColor.redColor().CGColor
outLayer.addSublayer(redLayer)
var fromValue = CATransform3DIdentity
fromValue.m34 = -1 / 500.0
fromValue = CATransform3DRotate(fromValue, 0, 0, 1, 0)
var toValue = CATransform3DIdentity
toValue.m34 = -1 / 500.0
toValue = CATransform3DRotate(toValue, CGFloat( M_PI ), 0, 1, 0)
var basicAnimation = CABasicAnimation(keyPath: "transform")
basicAnimation.duration = 1.0
basicAnimation.fromValue = NSValue(CATransform3D:fromValue)
basicAnimation.toValue = NSValue(CATransform3D:toValue)
outLayer.transform = toValue
outLayer.addAnimation(basicAnimation, forKey: "transform3D")


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

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


  它還有一個locations屬性,可以設置每個漸變色的間距,這個數組的長度需要和colors數組的長度相同,location的值是按endPoint的值來說的,不是是多少及時多少
CAReplicatorLayer
  CAReplicatorLayer可以使用在需要創建多個同樣的layer只是軌迹顔色有規則的變化的時候,它會把它的子圖層有規律的重複展示出來,而可以設置它重複的次數/每次漸變的顔色遞增遞減值/每次transform變換的路徑.

repeatLayer = CAReplicatorLayer()
repeatLayer.frame = CGRectMake(50, 50, 300, 300)
repeatLayer.backgroundColor = UIColor.grayColor().CGColor
self.view.layer.addSublayer(repeatLayer)
var transform = CATransform3DIdentity
transform = CATransform3DTranslate(transform, 0, 100, 0);
transform = CATransform3DRotate(transform, CGFloat( M_PI / 5.0 ), 0, 0, 1);
transform = CATransform3DTranslate(transform, 0, -100, 0);
repeatLayer.instanceTransform = transform;
repeatLayer.instanceCount = 10
repeatLayer.instanceBlueOffset = -0.1
repeatLayer.instanceRedOffset = -0.1
var layer = CALayer()
layer.frame = CGRect(x: 125, y: 125, width: 50, height: 50)
layer.backgroundColor = UIColor.whiteColor().CGColor
repeatLayer.addSublayer(layer)


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

reflectionLayer = CAReplicatorLayer()
var img = UIImage(named: "3333.jpg")
reflectionLayer.frame = CGRectMake((self.view.bounds.size.width - img!.size.width) / 2 , 100, img!.size.width, img!.size.height * 1.5)
reflectionLayer.backgroundColor = UIColor.grayColor().CGColor
self.view.layer.addSublayer(reflectionLayer)
var transform = CATransform3DIdentity
transform = CATransform3DScale(transform, 1, -0.5, 1);
transform = CATransform3DTranslate(transform, 0, -img!.size.height * 3 / 4 + 2, 0.0);
reflectionLayer.instanceTransform = transform;
reflectionLayer.instanceCount = 2
var imageLayer = CALayer()
imageLayer.frame = CGRect(x: 0, y: 0, width: img!.size.width, height: img!.size.height)
imageLayer.backgroundColor = UIColor.whiteColor().CGColor
imageLayer.contents = img!.CGImage
//layer.anchorPoint = CGPointMake(0, 0)
reflectionLayer.addSublayer(imageLayer)
//設置透明度,在外面用個層來設置
var gradientLayer = CAGradientLayer()
gradientLayer.colors = [UIColor.whiteColor().colorWithAlphaComponent(0.2).CGColor, UIColor.whiteColor().CGColor]
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)
self.view.layer.addSublayer(gradientLayer)
//設置文字
var textLayer = CATextLayer()
textLayer.frame = CGRectMake(80, 50, 200, 300)
self.view.layer.addSublayer(textLayer)
//設置它的屬性
textLayer.foregroundColor = UIColor.redColor().CGColor
textLayer.alignmentMode = kCAAlignmentJustified
textLayer.wrapped = true
//它的font是CGFont類型,需要大小字體分開設置
var font = UIFont.systemFontOfSize(24)
textLayer.font = CGFontCreateWithFontName(font.fontName)
textLayer.fontSize = font.pointSize
var textStr = "What a fuck!"
textLayer.string = textStr
//它contentScale默認是1,爲了讓它以retina的質量來顯示,設置爲2
textLayer.contentsScale = UIScreen.mainScreen().scale
imageLayer.addSublayer(textLayer)
var basicAnimation = CABasicAnimation(keyPath: "position.y")
basicAnimation.duration = 2.0
basicAnimation.fromValue = Float( textLayer.position.y )
var toValue:Float = Float( textLayer.position.y + 100.0)
basicAnimation.toValue = NSNumber(float: toValue)
basicAnimation.removedOnCompletion = true
basicAnimation.fillMode = kCAFillModeForwards
textLayer.addAnimation(basicAnimation, forKey: nil)
// textLayer.frame.origin.y = CGFloat( toValue)
textLayer.position = CGPointMake(textLayer.position.x, textLayer.position.y + 100.0)


CAScrollLayer
  CAScrollLayer和UIScrollView類似,它和CALayer相比多了個scrollPoint的方法,如果要用這個方法可以使用CAScrollLayer
NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: NSSelectorFromString("setPosition"), userInfo: nil, repeats: false)
func setPosition () {
self.scrollLayer.scrollToPoint(CGPointMake(0, 100))
}
CATiledLayer
  CATiledLayer的可以做到圖片/PDF等的分割顯示,如果一個一張圖片分辨率超過2048*2048(因平台不同),超過了OpenGL最大紋理尺寸,所以會有效能問題,一個PDF一般也比較大,所以容易出現效能問題(後面會單獨寫一個demo)
CAEmitterLayer
  CAEmitterLayer能模仿粒子反射,如果火焰等,能控制粒子顔色/放射的速率,透明度,方向,個數等.

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


CAEAGLLayer
  它是一個提供用OpenGL ES來繪圖的layer,它可以預先假設要繪制的類型,快速繪制,它可以配合GLKit中的CLKView使用,具體demo專門寫.
AVFoundation
  它是foundation框架裏的,但是和layer的使用是一致的,demo如下

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


更多相關文章
  • css3+html5 實現變形與動畫教程
    本文是我們詳細介紹一下 css3+html5實現動畫的原理及實例的圖解教程,css3制作動畫的幾個屬性:變形(transform),過渡(transition)和動畫(animation)等.transform變形.transform英文意思:改變,變形.css3中transform注意包括以下幾種 ...
  • 三星手機Galaxy J7如何使用動畫GIF拍攝功能(J7008)
    J7如何使用動畫GIF拍攝功能?三星手機J7008支持動畫GIF拍攝功能,是指通過連續拍攝的多張照片依次顯示的原理,形成動態播放效果.若想使用該功能,請按照以下步驟操作1.在待機頁面下,點擊[照相機]. 2.點擊[模式]. 3.向上滑動模式菜單,選擇[動畫GIF]. 4.長按[照相機]圖標,將智能地
  • 用PNChart生成簡潔的的iOS圖表 帶動畫效果
    PNChart 可以在 iOS 下實現效果不錯的曲線圖和柱狀圖,可以動態生成圖表.本文我們來簡單看一下 PNChart生成簡潔高效有動畫效果的iOS圖表庫.先來看看PNChart的示意圖導入pod導入相對簡單,要手動導入這個庫,先下載下來(https://github.com/kevinzhow/P ...
  • iOS開發中類簇(Class Cluster)基礎、應用、使用心得
    類簇是一群隱藏在通用接口下的與實現相關的類,本文我們介紹iOS開發中類簇的基礎概念.子類,iOS開發中類簇的應用,以及使用心得.iOS開發中類簇(Class Cluster)類簇(Class Cluster)是定義相同的接口並提供相同功能的一組類的集合,僅公開接口的抽象類也可以稱之爲類簇的公共類,每 ...
  • Beamer  使用 tikz 宏包實現畫圖和動畫實例
    無意之中搜索到tikz這個宏包,它可以在beamer中用來繪制圖表,還可以結合到beame
  • WP8.1開發教程二: MapControl視圖控件和Animation動畫實例應用
    本教程來講講WP8.1的MapControl視圖控件和Animation動畫應用開發.Ma
  • 利用Photoshop制作GIF動畫圖片教程
    利用Photoshop制作GIF動畫圖片教程,制作動畫之前需要先把掃描的螢幕制作出來.動畫
  • 本文章給大家介紹一篇關于iOS 畫面切換的各種動畫效果附私有API,希望此教程對大家會有所幫助哦.ios的畫面切換的動畫效果的API主要通過調用系統已定義的動畫效果實現,這些效果已基本囊括開發的需求,如果需要更加複雜的效果,可以考慮CATransition來實現以下是基本的四種效果kCATransi ...
一周排行
  • 以前查詢mysql的時候,一般會用order by來進行排序,如果我們不需要對字段進行排序,應該怎麽辦呢?這個時候就得用order by null了.order by null用途是強制對查詢結果禁用排序.通過exp ...
  • ashx頁面中獲取session值是.net開發者們會常用到的一個問題,對于初學者可能有一些不理解,下文一聚教程小編爲各位介紹ashx頁面中獲取session值例子,希望文章能夠幫助到大家.1-在 aspx和aspx ...
  • 本文章給大家介紹一下關于數據庫sql語句to_char優化[mysql和oracle ]方法,有需要了解的同學可參考.最早發現這個問題是在買買提分析中,如果 在數據庫sql語句中用 代碼如下 select * fro
  • 关于sysctl.conf的优化方案在网上搜索一大堆,大多都是抄来抄去而且不全,为了不误导新手,本人经过两天的整理,查了N多资料,然后将最常用的功能总结归纳.Sysctl是一个允许您改变正在运行中的Linux系统的接 ...
  • 昨天有一位朋友問怎麽給爲vsftpd增加用戶呢,小編今天給大家介紹在ubuntu中爲vsftpd增加用戶的具體操作過程詳細介紹介紹,有需了解的朋友可進入參考.1.建立本地虛擬用戶代碼: 代碼如下 useradd -d ...
  • 下面我們來看看關于Bootstrap入門之Bootstrap3.0學習教程,希望例子能夠幫助到各位朋友,有興趣的朋友可以和小編來看看吧.菜單下拉菜單將下拉菜單觸發器和下拉菜單都包裹在.dropdown裏,然後添加組成 ...
  • 下面來給各位同學介紹關于phpmyadmin無法登錄提示please check errors given in your PHP and/or webserver,希望例子對各位有幫助.今天幫別人弄網站的時候要修改
  • 第一 js延遲載入 代碼如下: 代碼如下 <script language="網頁特效" src="" id="my"></script& ...
  • htmlspecialchars 和 htmlentities 的區別分析htmlentities() 函數把字符轉換爲 HTML 實體.htmlspecialchars() 函數把一些預定義的字符轉換爲 HTML
  • jquery load()用法$('#result').load('ajax/test.html', function() { alert('load was performed.');});調用load方法的完整格 ...