示例
#5:CAGradientLayer
CAGradientLayer简化了混合两种或更多颜色的工作,尤其适用于背景。要配置渐变色,你需要分配一个CGColor数组,以及标识渐变图层起止点的startPoint和endPoint。
注意:startPoint和endPoint并不是明确的点,而是用单位坐标空间定义,在绘制时映射到图层边界。也就是说x值为1表示点在图层右边缘,y值为1表示点在图层下边缘。
CAGradientLayer包含type属性,虽说该属性只有kCAGradientLayerAxial一个选择,由数组中的各颜色产生线性过渡渐变。
具体含义是渐变过渡沿startPoint到endPoint的向量A方向产生,设B与A垂直,则各条B平行线上的所有点颜色相同。
此外,locations属性可以使用一个数组(元素取值范围0到1),指定渐变图层参照colors顺序取用下一个过渡点颜色的位置。
未设定时默认会平均分配过渡点。一旦设定就必须与colors的数量保持一致,否则会出错。 :[
下面是创建渐变图层的例子:
let gradientLayer = CAGradientLayer() gradientLayer.frame = someView.bounds gradientLayer.colors = [cgColorForRed(209.0, green: 0.0, blue: 0.0), cgColorForRed(255.0, green: 102.0, blue: 34.0), cgColorForRed(255.0, green: 218.0, blue: 33.0), cgColorForRed(51.0, green: 221.0, blue: 0.0), cgColorForRed(17.0, green: 51.0, blue: 204.0), cgColorForRed(34.0, green: 0.0, blue: 102.0), cgColorForRed(51.0, green: 0.0, blue: 68.0)] gradientLayer.startPoint = CGPoint(x: 0, y: 0) gradientLayer.endPoint = CGPoint(x: 0, y: 1) someView.layer.addSublayer(gradientLayer) |
func cgColorForRed(red: CGFloat, green: CGFloat, blue: CGFloat) -> AnyObject { return UIColor(red: red/255.0, green: green/255.0, blue: blue/255.0, alpha: 1.0).CGColor as AnyObject } |
上述代码创建一个渐变图层,框架设为someView边界,指定颜色数组,设置起止点,添加图层到视图结构树。效果如下:
五彩缤纷,姹紫嫣红!
图层演示应用中,你可以随意修改起止点、颜色和过渡点:
示例 #6:CAReplicatorLayer
CAReplicatorLayer能够以特定次数复制图层,可以用来创建一些很棒的效果。
每个图层复件的颜色和位置都可以改动,而且可以在总复制图层之后延迟绘制,营造一种动画效果。还可以利用深度,创造三维效果。举个例子
// 1 let replicatorLayer = CAReplicatorLayer() replicatorLayer.frame = someView.bounds // 2 replicatorLayer.instanceCount = 30 replicatorLayer.instanceDelay = CFTimeInterval(1 / 30.0) replicatorLayer.preservesDepth = false replicatorLayer.instanceColor = UIColor.whiteColor().CGColor // 3 replicatorLayer.instanceRedOffset = 0.0 replicatorLayer.instanceGreenOffset = -0.5 replicatorLayer.instanceBlueOffset = -0.5 replicatorLayer.instanceAlphaOffset = 0.0 // 4 let angle = Float(M_PI * 2.0) / 30 replicatorLayer.instanceTransform = CATransform3DMakeRotation(CGFloat(angle), 0.0, 0.0, 1.0) someView.layer.addSublayer(replicatorLayer) // 5 let instanceLayer = CALayer() let layerWidth: CGFloat = 10.0 let midX = CGRectGetMidX(someView.bounds) - layerWidth / 2.0 instanceLayer.frame = CGRect(x: midX, y: 0.0, width: layerWidth, height: layerWidth * 3.0) instanceLayer.backgroundColor = UIColor.whiteColor().CGColor replicatorLayer.addSublayer(instanceLayer) // 6 let fadeAnimation = CABasicAnimation(keyPath: "opacity") fadeAnimation.fromValue = 1.0 fadeAnimation.toValue = 0.0 fadeAnimation.duration = 1 fadeAnimation.repeatCount = Float(Int.max) // 7 instanceLayer.opacity = 0.0 instanceLayer.addAnimation(fadeAnimation, forKey: "FadeAnimation") |
以上代码:
创建一个CAReplicatorLayer实例,设框架为someView边界。
设复制图层数instanceCount和绘制延迟,设图层为2D(preservesDepth = false),实例颜色为白色。
为陆续的实例复件设置RGB颜色偏差值(默认为0,即所有复件保持颜色不变),不过这里实例初始颜色为白色,即RGB都为1.0,所以偏差值设红色为0,绿色和蓝色为相同负数会使其逐渐现出红色,alpha透明度偏差值的变化也与此类似,针对陆续的实例复件。
创建旋转变换,使得实例复件按一个圆排列。
创建供复制图层使用的实例图层,设置框架,使第一个实例在someView边界顶端水平中心处绘制,另外设置实例颜色,把实例图层添加到复制图层。
创建一个透明度由1(不透明)过渡为0(透明)的淡出动画。
设实例图层透明度为0,使得每个实例在绘制和改变颜色与alpha前保持透明。
这段代码会实现这样的东西:
图层演示应用中,你可以改动这些属性:
示例 #7:CATiledLayer
CATiledLayer以图块(tile)为单位异步绘制图层内容,对超大尺寸图片或者只能在视图中显示一小部分的内容效果拔群,因为不用把内容完全载入内存就可以看到内容。
处理绘制有几种方法,一种是重写UIView,使用CATiledLayer绘制图块填充视图背景,如下:
// In ViewController.swift import UIKit class ViewController: UIViewController { // 1 @IBOutlet weak var tiledBackgroundView: TiledBackgroundView! } // In TiledBackgroundView.swift import UIKit class TiledBackgroundView: UIView { let sideLength = CGFloat(50.0) // 2 override class func layerClass() -> AnyClass { return CATiledLayer.self } // 3 required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) srand48(Int(NSDate().timeIntervalSince1970)) let layer = self.layer as CATiledLayer let scale = UIScreen.mainScreen().scale layer.contentsScale = scale layer.tileSize = CGSize(width: sideLength * scale, height: sideLength * scale) } // 4 override func drawRect(rect: CGRect) { let context = UIGraphicsGetCurrentContext() var red = CGFloat(drand48()) var green = CGFloat(drand48()) var blue = CGFloat(drand48()) CGContextSetRGBFillColor(context, red, green, blue, 1.0) CGContextFillRect(context, rect) } } |
代码解释:
tiledBackgroundView位于 (150, 150) ,宽高均为300。
重写layerClass(),令该视图创建的图层实例为CATiledLayer。
设置rand48()的随机数种子,用于在drawRect()中生成随机颜色。CATiledLayer类型转换,缩放图层内容,设置图块尺寸,适应屏幕。
重写drawRect(),以随机色块填充视图。
代码绘制6×6随机色块方格,最终效果如下:
图层演示应用中除此之外还可以在图层背景上绘制轨迹:
在视图中放大时,上述截图中的星星图案会变得模糊:
产生模糊的根源是图层的细节层次(level of detail,简称LOD),CATiledLayer有两个相关属性:levelsOfDetail和levelsOfDetailBias。
levelsOfDetail顾名思义,指图层维护的LOD数目,默认值为1,每进一级会对前一级分辨率的一半进行缓存,图层的levelsOfDetail最大值,也就是最底层细节,对应至少一个像素点。
而levelsOfDetailBias指的是该图层缓存的放大LOD数目,默认为0,即不会额外缓存放大层次,每进一级会对前一级两倍分辨率进行缓存。
例如,设上述分块图层的levelsOfDetailBias为5会缓存2x、4x、8x、16x和32x的放大层次,放大的图层效果如下:
不错吧?别着急,还没讲完呢。
CATiledLayer裁刀,买不了吃亏,买不了上当,只要998…(译注:此处内容稍作本地化处理,原文玩的是1978年美国Ginsu刀具的梗,堪称询价型电视购物广告的万恶之源。)
:]
开个玩笑。CATiledLayer还有一个更实用的功能:异步绘制图块,比如在滚动视图中显示一张超大图片。
在用户滚动画面时,要让分块图层知道哪些图块需要绘制,写代码在所难免,不过换来性能提升也值了。
图层演示应用的UIImage+TileCutter.swift中包含一个UIImage扩展,教程编纂组成员Nick
Lockwood在著作iOS Core Animation: Advanced Techniques的一个终端应用程序中利用了这段代码。
代码的职责是把原图片拆分成指定尺寸的方块,按行列位置命名图块,比如第三行第七列的图块windingRoad62.png(索引从零开始)。
有了这些图块,我们可以自定义一个UIView子类,绘制分块图层:
mport UIKit class TilingViewForImage: UIView { // 1 let sideLength = CGFloat(640.0) let fileName = "windingRoad" let cachesPath = NSSearchPathForDirectoriesInDomains
(.CachesDirectory, .UserDomainMask, true)[0] as String // 2 override class func layerClass() -> AnyClass { return CATiledLayer.self } // 3 required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) let layer = self.layer as CATiledLayer layer.tileSize = CGSize(width: sideLength, height: sideLength) } // 4 override func drawRect(rect: CGRect) { let firstColumn = Int(CGRectGetMinX(rect) / sideLength) let lastColumn = Int(CGRectGetMaxX(rect) / sideLength) let firstRow = Int(CGRectGetMinY(rect) / sideLength) let lastRow = Int(CGRectGetMaxY(rect) / sideLength) for row in firstRow...lastRow { for column in firstColumn...lastColumn { if let tile = imageForTileAtColumn(column, row: row) { let x = sideLength * CGFloat(column) let y = sideLength * CGFloat(row) let point = CGPoint(x: x, y: y) let size = CGSize(width: sideLength, height: sideLength) var tileRect = CGRect(origin: point, size: size) tileRect = CGRectIntersection(bounds, tileRect) tile.drawInRect(tileRect) } } } } func imageForTileAtColumn(column: Int, row: Int) -> UIImage? { let filePath = "\(cachesPath)/\(fileName)_\(column)_\(row)" return UIImage(contentsOfFile: filePath) } } |
以上代码:
创建属性,分别是图块边长、原图文件名、供TileCutter扩展保存图块的缓存文件夹路径。
重写layerClass()返回CATiledLayer。
实现init(_:),把视图的图层转换为分块图层,设置图块大小。注意此处不必设置contentsScale适配屏幕,因为是直接修改视图自身的图层,而不是手动创建子图层。
重写drawRect(),按行列绘制各个图块。
像这样,原图大小的自定义视图就可以塞进一个滚动视图:
多亏CATiledLayer,滚动5120 x 3200的大图也会这般顺滑:
如你所见,快速滚动时绘制图块的过程还是很明显,你可以利用更小的分块(上述例子中分块为640 x 640),或者自己创建一个CATiledLayer子类,重写fadeDuration()返回0:
class TiledLayer: CATiledLayer { override class func fadeDuration() -> CFTimeInterval { return 0.0 } } |
示例 #8:CAShapeLayer
CAShapeLayer利用可缩放的矢量路径进行绘制,绘制速度比使用图片快很多,还有个好处是不用分别提供常规、@2x和@3x版本的图片,好用。
另外还有各种属性,让你可以自定线粗、颜色、虚实、线条接合方式、闭合线条是否形成闭合区域,还有闭合区域要填充何种颜色等。举例如下
import UIKit class ViewController: UIViewController { @IBOutlet weak var someView: UIView! // 1 let rwColor = UIColor(red: 11/255.0, green: 86/255.0, blue: 14/255.0, alpha: 1.0) let rwPath = UIBezierPath() let rwLayer = CAShapeLayer() // 2 func setUpRWPath() { rwPath.moveToPoint(CGPointMake(0.22, 124.79)) rwPath.addLineToPoint(CGPointMake(0.22, 249.57)) rwPath.addLineToPoint(CGPointMake(124.89, 249.57)) rwPath.addLineToPoint(CGPointMake(249.57, 249.57)) rwPath.addLineToPoint(CGPointMake(249.57, 143.79)) rwPath.addCurveToPoint(CGPointMake(249.37, 38.25),
controlPoint1: CGPointMake(249.57, 85.64), controlPoint2: CGPointMake(249.47, 38.15)) rwPath.addCurveToPoint(CGPointMake(206.47, 112.47),
controlPoint1: CGPointMake(249.27, 38.35), controlPoint2: CGPointMake(229.94, 71.76)) rwPath.addCurveToPoint(CGPointMake(163.46, 186.84),
controlPoint1: CGPointMake(182.99, 153.19), controlPoint2: CGPointMake(163.61, 186.65)) rwPath.addCurveToPoint(CGPointMake(146.17, 156.99),
controlPoint1: CGPointMake(163.27, 187.03), controlPoint2: CGPointMake(155.48, 173.59)) rwPath.addCurveToPoint(CGPointMake(128.79, 127.08),
controlPoint1: CGPointMake(136.82, 140.43), controlPoint2: CGPointMake(129.03, 126.94)) rwPath.addCurveToPoint(CGPointMake(109.31, 157.77),
controlPoint1: CGPointMake(128.59, 127.18), controlPoint2: CGPointMake(119.83, 141.01)) rwPath.addCurveToPoint(CGPointMake(89.83, 187.86),
controlPoint1: CGPointMake(98.79, 174.52), controlPoint2: CGPointMake(90.02, 188.06)) rwPath.addCurveToPoint(CGPointMake(56.52, 108.28),
controlPoint1: CGPointMake(89.24, 187.23), controlPoint2: CGPointMake(56.56, 109.11)) rwPath.addCurveToPoint(CGPointMake(64.02, 102.25),
controlPoint1: CGPointMake(56.47, 107.75), controlPoint2: CGPointMake(59.24, 105.56)) rwPath.addCurveToPoint(CGPointMake(101.42, 67.57),
controlPoint1: CGPointMake(81.99, 89.78), controlPoint2: CGPointMake(93.92, 78.72)) rwPath.addCurveToPoint(CGPointMake(108.38, 30.65),
controlPoint1: CGPointMake(110.28, 54.47), controlPoint2: CGPointMake(113.01, 39.96)) rwPath.addCurveToPoint(CGPointMake(10.35, 0.41),
controlPoint1: CGPointMake(99.66, 13.17), controlPoint2: CGPointMake(64.11, 2.16)) rwPath.addLineToPoint(CGPointMake(0.22, 0.07)) rwPath.addLineToPoint(CGPointMake(0.22, 124.79)) rwPath.closePath() } // 3 func setUpRWLayer() { rwLayer.path = rwPath.CGPath rwLayer.fillColor = rwColor.CGColor rwLayer.fillRule = kCAFillRuleNonZero rwLayer.lineCap = kCALineCapButt rwLayer.lineDashPattern = nil rwLayer.lineDashPhase = 0.0 rwLayer.lineJoin = kCALineJoinMiter rwLayer.lineWidth = 1.0 rwLayer.miterLimit = 10.0 rwLayer.strokeColor = rwColor.CGColor } override func viewDidLoad() { super.viewDidLoad() // 4 setUpRWPath() setUpRWLayer() someView.layer.addSublayer(rwLayer) } } |
代码解释:
创建颜色、路径、图形图层对象。
绘制图形图层路径。如果不喜欢编写生硬的绘图代码的话,你可以尝试PaintCode这款软件,可以利用简便的工具进行可视化绘制,支持导入现有的矢量图(SVG)和Photoshop(PSD)文件,并自动生成代码。
设置图形图层。路径设为第二步中绘制的CGPath路径,填充色设为第一步中创建的CGColor颜色,填充规则设为非零(non-zero),即默认填充规则。
填充规则共有两种,另一种是奇偶(even-odd)。不过示例代码中的图形没有相交路径,两种填充规则的结果并无差异。
非零规则记从左到右的路径为+1,从右到左的路径为-1,累加所有路径值,若总和大于零,则填充路径围成的图形。
从结果上来讲,非零规则会填充图形内部所有的点。
奇偶规则计算围成图形的路径交叉数,若结果为奇数则填充。这样讲有些晦涩,还是有图有真相:
右图围成中间五边形的路径交叉数为偶数,故中间没有填充,而围成每个三角的路径交叉数为奇数,故三角部分填充颜色。
调用路径绘制和图层设置代码,并把图层添加到视图结构树。
上述代码绘制raywenderlich.com的图标:
顺便看看使用PaintCode的效果图:
图层演示应用中,你可以随意修改很多CAShapeLayer属性:
注:我们先跳过演示应用中的下一个示例,因为CAEAGLLayer多少显得有些过时了,iOS 8 Metal框架有更先进的CAMetalLayer。在此推荐iOS
8 Metal入门教程。
示例 #9:CATransformLayer
CATransformLayer不像其他图层类一样把子图层结构平面化,故适宜绘制3D结构。变换图层本质上是一个图层容器,每个子图层都可以应用自己的透明度和空间变换,而其他渲染图层属性(如边宽、颜色)会被忽略。
变换图层本身不支持点击测试,因为无法直接在触摸点和平面坐标空间建立映射,不过其中的子图层可以响应点击测试,例如:
import UIKit class ViewController: UIViewController { @IBOutlet weak var someView: UIView! // 1 let sideLength = CGFloat(160.0) var redColor = UIColor.redColor() var orangeColor = UIColor.orangeColor() var yellowColor = UIColor.yellowColor() var greenColor = UIColor.greenColor() var blueColor = UIColor.blueColor() var purpleColor = UIColor.purpleColor() var transformLayer = CATransformLayer() // 2 func setUpTransformLayer() { var layer = sideLayerWithColor(redColor) transformLayer.addSublayer(layer) layer = sideLayerWithColor(orangeColor) var transform = CATransform3DMakeTranslation(sideLength / 2.0, 0.0, sideLength / -2.0) transform = CATransform3DRotate(transform, degreesToRadians(90.0), 0.0, 1.0, 0.0) layer.transform = transform transformLayer.addSublayer(layer) layer = sideLayerWithColor(yellowColor) layer.transform = CATransform3DMakeTranslation(0.0, 0.0, -sideLength) transformLayer.addSublayer(layer) layer = sideLayerWithColor(greenColor) transform = CATransform3DMakeTranslation(sideLength / -2.0, 0.0, sideLength / -2.0) transform = CATransform3DRotate(transform, degreesToRadians(90.0), 0.0, 1.0, 0.0) layer.transform = transform transformLayer.addSublayer(layer) layer = sideLayerWithColor(blueColor) transform = CATransform3DMakeTranslation(0.0, sideLength / -2.0, sideLength / -2.0) transform = CATransform3DRotate(transform, degreesToRadians(90.0), 1.0, 0.0, 0.0) layer.transform = transform transformLayer.addSublayer(layer) layer = sideLayerWithColor(purpleColor) transform = CATransform3DMakeTranslation(0.0, sideLength / 2.0, sideLength / -2.0) transform = CATransform3DRotate(transform, degreesToRadians(90.0), 1.0, 0.0, 0.0) layer.transform = transform transformLayer.addSublayer(layer) transformLayer.anchorPointZ = sideLength / -2.0 applyRotationForXOffset(16.0, yOffset: 16.0) } // 3 func sideLayerWithColor(color: UIColor) -> CALayer { let layer = CALayer() layer.frame = CGRect(origin: CGPointZero, size: CGSize(width: sideLength, height: sideLength)) layer.position = CGPoint(x: CGRectGetMidX(someView.bounds), y: CGRectGetMidY(someView.bounds)) layer.backgroundColor = color.CGColor return layer } func degreesToRadians(degrees: Double) -> CGFloat { return CGFloat(degrees * M_PI / 180.0) } // 4 func applyRotationForXOffset(xOffset: Double, yOffset: Double) { let totalOffset = sqrt(xOffset * xOffset + yOffset * yOffset) let totalRotation = CGFloat(totalOffset * M_PI / 180.0) let xRotationalFactor = CGFloat(totalOffset) / totalRotation let yRotationalFactor = CGFloat(totalOffset) / totalRotation let currentTransform = CATransform3DTranslate(transformLayer.sublayerTransform, 0.0, 0.0, 0.0) let rotationTransform = CATransform3DRotate(transformLayer.sublayerTransform, totalRotation, xRotationalFactor * currentTransform.m12 - yRotationalFactor * currentTransform.m11, xRotationalFactor * currentTransform.m22 - yRotationalFactor * currentTransform.m21, xRotationalFactor * currentTransform.m32 - yRotationalFactor * currentTransform.m31) transformLayer.sublayerTransform = rotationTransform } // 5 override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { if let location = touches.anyObject()?.locationInView(someView) { for layer in transformLayer.sublayers { if let hitLayer = layer.hitTest(location) { println("Transform layer tapped!") break } } } } override func viewDidLoad() { super.viewDidLoad() // 6 setUpTransformLayer() someView.layer.addSublayer(transformLayer) } } |
上述代码解释:
创建属性,分别为立方体的边长、每个面的颜色,还有一个变换图层。
创建六个面,旋转后添加到变换图层,构成立方体,然后设置变换图层的z轴锚点,旋转立方体,将其添加到视图结构树。
辅助代码,用来创建指定颜色的面,还有角度和弧度的转换。在变换代码中利用弧度转换函数在某种程度上可以增加代码可读性。
:]
基于指定xy偏移的旋转,注意变换应用对象设为sublayerTransform,即变换图层的子图层。
监听触摸,遍历变换图层的子图层,对每个图层进行点击测试,一旦成功相应立即跳出循环,不用继续遍历。
设置变换图层,添加到视图结构树。
注:currentTransform.m##是啥?问得好,是CATransform3D属性,代表矩阵元素。想学习如上代码中的矩阵变换,请参考RW教程组成员Rich
Turton的三维变换娱乐教学,还有Mark Pospesel的初识矩阵项目。
在250 x 250的someView视图中运行上述代码结果如下:
再试试点击立方体的任意位置,控制台会输出“Transform layer tapped!”信息。
图层演示应用中可以调整透明度,此外Bill Dudney轨迹球工具, Swift移植版可以基于简单的用户手势应用三维变换。
示例 #10:CAEmitterLayer
CAEmitterLayer渲染的动画粒子是CAEmitterCell实例。CAEmitterLayer和CAEmitterCell都包含可调整渲染频率、大小、形状、颜色、速率以及生命周期的属性。示例如下:
import UIKit class ViewController: UIViewController { // 1 let emitterLayer = CAEmitterLayer() let emitterCell = CAEmitterCell() // 2 func setUpEmitterLayer() { emitterLayer.frame = view.bounds emitterLayer.seed = UInt32(NSDate().timeIntervalSince1970) emitterLayer.renderMode = kCAEmitterLayerAdditive emitterLayer.drawsAsynchronously = true setEmitterPosition() } // 3 func setUpEmitterCell() { emitterCell.contents = UIImage(named: "smallStar")?.CGImage emitterCell.velocity = 50.0 emitterCell.velocityRange = 500.0 emitterCell.color = UIColor.blackColor().CGColor emitterCell.redRange = 1.0 emitterCell.greenRange = 1.0 emitterCell.blueRange = 1.0 emitterCell.alphaRange = 0.0 emitterCell.redSpeed = 0.0 emitterCell.greenSpeed = 0.0 emitterCell.blueSpeed = 0.0 emitterCell.alphaSpeed = -0.5 let zeroDegreesInRadians = degreesToRadians(0.0) emitterCell.spin = degreesToRadians(130.0) emitterCell.spinRange = zeroDegreesInRadians emitterCell.emissionRange = degreesToRadians(360.0) emitterCell.lifetime = 1.0 emitterCell.birthRate = 250.0 emitterCell.xAcceleration = -800.0 emitterCell.yAcceleration = 1000.0 } // 4 func setEmitterPosition() { emitterLayer.emitterPosition = CGPoint(x: CGRectGetMidX(view.bounds), y: CGRectGetMidY(view.bounds)) } func degreesToRadians(degrees: Double) -> CGFloat { return CGFloat(degrees * M_PI / 180.0) } override func viewDidLoad() { super.viewDidLoad() // 5 setUpEmitterLayer() setUpEmitterCell() emitterLayer.emitterCells = [emitterCell] view.layer.addSublayer(emitterLayer) } // 6 override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) { setEmitterPosition() } } |
以上代码解析:
1.创建粒子发射器图层和粒子胞(Creates an emitter layer and cell.)。
2.按照下方步骤设置粒子发射器图层:
为随机数生成器提供种子,随机调整粒子胞的某些属性,如速度。
在图层背景色和边界之上按renderMode指定的顺序渲染粒子胞。
注:渲染模式默认为无序(unordered),其他模式包括旧粒子优先(oldest first),新粒子优先(oldest
last),按z轴位置从后至前(back to front)还有叠加式渲染(additive)。
由于粒子发射器需要反复重绘大量粒子胞,设drawsAsynchronously为true会提升性能。
然后借助第四条中会提到的辅助方法设置发射器位置,这个例子有助于理解把drawsAsynchronously设为true为何能够提升性能和动画流畅度。
3.这段代码设了不少东西。
配置粒子胞,设内容为图片(图片在图层演示项目中)。
指定初速及其变化量范围(velocityRange),发射器图层利用上面提到的随机数种子创建随机数生成器,在范围内产生随机值(初值+/-变化量范围),其他以“Range”结尾的相关属性的随机化规则类似。
设颜色为黑色,使自变色(variance)与默认的白色形成对比,白色形成的粒子亮度过高。
利用随机化范围设置颜色,指定自变色范围,颜色速度值表示粒子胞生命周期内颜色变化快慢。
接下来这几行代码指定粒子胞分布范围,一个全圆锥。设置粒子胞转速和发射范围,发射范围emissionRange属性的弧度值决定粒子胞分布空间。
设粒子胞生命周期为1秒,默认值为0,表示粒子胞不会出现。birthRate也类似,以秒为单位,默认值为0,为使粒子胞显示出来,必须设成正数。
最后设xy加速度,这些值会影响已发射粒子的视角。
4.把角度转换成弧度的辅助方法,还有设置粒子胞位置为视图中点。
5.设置发射器图层和粒子胞,把粒子胞添加到图层,然后把图层添加到视图结构树。
6.iOS 8的新方法,处理当前设备形态集(trait collection)的变化,比如设备旋转。不熟悉形态集的话可以参阅iOS
8教程。
总算说完了!信息量很大,但相信各位聪明的读者可以高效吸收。
上述代码运行效果如下:
图层演示应用中,你可以随意调节很多属性:
|