Core Animation总结(一)图层变换(平面 立体)

Core Animation总结(二)专用图层

Core Animation总结(三)动画

Core Animation总结(四)

Core Animation总结(五)性能

Core Animation总结(六)知识点整理

#Core Animation

###CALayer 如果将UIView说成是视图,那么CALayer就是图层了。每一个 UIView 的身后对应一个 Core Animation 框架中的 CALayer;每一个 CALayer 都是 UIView 的代理。 在iOS开发中,处理的一个又一个UIView,实际是在操作CALayer。那么为什么不直接对CALayer进行编程呢?那是因为CALayer继承自NSObject,主要是用于图层的处理以及动画,而UIView继承自UIResponder,可以处理交互事件。 由此,可以认为UIView就是对CALayer的一个简单封装,图像绘制、动画都是CALayer做的。有过开发经验的朋友都知道,苹果在UIView里面封装了一套动画接口,但是利用这些接口,只是可以做一些简单、不灵活的动画。如果想在底层做一些改变,想实现一些特别的动画,这是除了学习Core Animation之外,别无选择。

向图层添加大量自定义效果可能会对性能产生影响。现在,我们将讨论 CALayer 的两个属性,它们可以帮助我们大幅度提高应用程序的性能。

首先,让我们来讨论下 drawsAsynchronously。这是属性在 CALayer 上指定了在绘制图层时 CPU 必须执行的那些操作是否需要在后台线程中执行的作用。如果这个属性被设置为 true,图层看起来与往常一样,但是绘制它所需的 CPU 计算将在后台线程中执行。如果你的应用中有一个需要大量重新绘制的视图(例如地图视图或表格视图),请将此项设为 true。

另一个属性是 shouldRasterize。这是 CALayer 上的另一个属性。它指定了是否应该对图层进行光栅化。当这个属性被设置为 true 的时候,图层只被绘制一次。每当图层被动画化的时候,图层不会被重绘,而是不断复用第一次绘制时的位图信息。如果你的应用中有一个视图不需要频繁重绘,则应将这个属性设置为 true。注意,当设置 shouldRasterize 时,图层的外观可能会在 Retina 屏幕的设备上有所不同。这是因为图层存在所谓的光栅化比例,这个比例用在图层发生光栅化的时候。要防止这种情况发生,把图层的 rasterizationScale 设置为 UIScreen.mainScreen().scale,这样在图层进行光栅化的时候会与屏幕绘制的比例保持一致。

注意,99% 的情况下你都不需要自己去设置这些属性。手动设置它们可能导致性能低下。如果你能确定视图或图层的绘制正在影响应用程序的性能,你也只能自行设置这两个属性中的一个。

###寄宿图 给contents赋CGImage的值不是唯一的设置寄宿图的方法。我们也可以直接用Core Graphics直接绘制寄宿图。 能够通过继承UIView并实现-drawRect:方法来自定义绘制。

// 创建 CALayer
let layer: CALayer = CALayer()
layer.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
layer.backgroundColor = UIColor.blue.cgColor
self.view.layer.addSublayer(layer)
layer.borderWidth=1/*contents 你还可以把一个图片分配给图层,以便在图层上展示图片如果你赋的不是CGImage,那么你得到的图层将是空白的。*/
layer.contents = UIImage(named: "test.png")?.cgImage/*CALayer与UIImageView.contentMode对应的属性叫做contentsGravity,和cotentMode一样,contentsGravity的目的是为了决定内容在图层的边界中怎么对齐,我们将使用kCAGravityResizeAspect,它的效果等同于UIViewContentModeScaleAspectFit, 同时它还能在图层中等比例拉伸以适应图层的边界。*/
layer.contentsGravity = kCAGravityResizeAspect
/*contentsScale属性定义了寄宿图的像素尺寸和视图大小的比例,默认情况下它是一个值为1.0的浮点数。当用代码的方式来处理寄宿图的时候,一定要记住要手动的设置图层的contentsScale属性*/
layer.contentsScale = UIScreen.main.scale
/*UIView.clipsToBounds 是指视图上的子视图,如果超出父视图的部分就截取掉GALayer.masksToBounds 是指视图的图层上的子图层,如果超出父图层的部分就截取掉*/
layer.masksToBounds = true
/*contentsRect 默认的是{0, 0, 1, 1},这意味着整个寄宿图默认都是可见的,如果我们指定一个小一点的矩形,图片就会被裁剪*/
layer.contentsRect = CGRect(x: 0, y: 0, width: 0.5, height: 0.5)
/*contentsCenter 是一个CGRect,它定义了一个固定的边框和一个在图层上可拉伸的区域。 改变contentsCenter的值并不会影响到寄宿图的显示,除非这个图层的大小改变了,你才看得到效果。默认情况下,contentsCenter是{0, 0, 1, 1},这意味着如果大小(由conttensGravity决定)改变了,那么寄宿图将会均匀地拉伸开。效果和UIImage里的-resizableImageWithCapInsets: 方法效果非常类似*/
layer.contentsCenter = CGRect(x: 0.25, y: 0.25, width: 0.5, height: 0.5)

###图层几何 #####布局 UIView有三个比较重要的布局属性:frame,bounds和center CALayer对应地叫做frame,bounds和position 为了能清楚区分,图层用了“position”,视图用了“center”,但是他们都代表同样的值 frame代表了图层的外部坐标(也就是在父图层上占据的空间) bounds是内部坐标({0, 0}通常是图层的左上角) center和position都代表了相对于父图层anchorPoint所在的位置 frame并不是一个非常清晰的属性,它其实是一个虚拟属性,是根据bounds,position和transform计算而来 当对图层做变换的时候,比如旋转或者缩放,frame实际上代表了覆盖在图层旋转之后的整个轴对齐的矩形区域,也就是说frame的宽高可能和bounds的宽高不再一致了

#####锚点 anchorPoint 默认来说,anchorPoint位于图层的中点,所以图层的将会以这个点为中心放置。 anchorPoint属性并没有被UIView接口暴露出来,这也是视图的position属性被叫做“center”的原因。但是图层的anchorPoint可以被移动

把anchorPoint置于图层frame的左上角,于是图层的内容将会向右下角的position方向移动,而不是居中了。

before:frame  = 10 10 40 50bounds    = 0    0 40 50position = 30 35anchorPoint = 0.5 .05
after:frame     = 30 35 40 50bounds    = 0    0 40 50position = 30 35anchorPoint = 0 0

以下是一个时钟的例子,时针分针秒针围绕中心转动

//
//  ViewController.swift
//  Demo
//
//  Created by joker on 2016/11/9.
//  Copyright © 2016年 joker. All rights reserved.
//
import UIKit
class ViewController: UIViewController {var h: UIView!var m: UIView!var s: UIView!var timer: Timer!func set1(){h = UIView(frame: CGRect(x: 200, y: 150, width: 5, height: 50))h.backgroundColor = UIColor.redm = UIView(frame: CGRect(x: 200, y: 130, width: 5, height: 70))m.backgroundColor = UIColor.greens = UIView(frame: CGRect(x: 200, y: 100, width: 5, height: 100))s.backgroundColor = UIColor.blueself.view.addSubview(h)self.view.addSubview(m)self.view.addSubview(s)h.layer.anchorPoint = CGPoint(x: 0.5, y: 0.9)m.layer.anchorPoint = CGPoint(x: 0.5, y: 0.9)s.layer.anchorPoint = CGPoint(x: 0.5, y: 0.9)}func tick(){let calendar: Calendar = Calendar(identifier: Calendar.Identifier.gregorian)let components: DateComponents = calendar.dateComponents(in: TimeZone.current, from: Date())let hoursAngle: CGFloat = CGFloat(components.hour!) / 12 * CGFloat.pi * 2let minsAngle: CGFloat = CGFloat(components.minute!) / 60 * CGFloat.pi * 2let secsAngle: CGFloat = CGFloat(components.second!) / 60 * CGFloat.pi * 2/*UIView的transform属性是一个CGAffineTransform类型,用于在二维空间做旋转,缩放和平移*/h.transform = CGAffineTransform(rotationAngle: hoursAngle)m.transform = CGAffineTransform(rotationAngle: minsAngle)s.transform = CGAffineTransform(rotationAngle: secsAngle)}func set2(){tick()timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.tick), userInfo: nil, repeats: true)}override func viewDidLoad() {super.viewDidLoad()set1()set2()}override func didReceiveMemoryWarning() {super.didReceiveMemoryWarning()// Dispose of any resources that can be recreated.}
}

#####坐标 和UIView严格的二维坐标系不同,CALayer存在于一个三维空间当中。除了我们已经讨论过的position和anchorPoint属性之外,CALayer还有另外两个属性,zPosition和anchorPointZ,二者都是在Z轴上描述图层位置的浮点类型。 zPosition最实用的功能就是改变图层的显示顺序了。在小于它的zPosition值的图层的前面

#####Hit Testing CALayer并不关心任何响应链事件,所以不能直接处理触摸事件或者手势。但是它有一系列的方法帮你处理事件 containsPoint

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {let point: CGPoint = (touches.first?.location(in: self.view))!// 坐标转换let layPoint = self.view.layer.convert(point, from: self.view.layer)/*containsPoint:接受一个在本图层坐标系下的CGPoint,如果这个点在图层frame范围内就返回YES*/if self.view.layer.contains(layPoint){print("in layer")}else{print("out layer")}/*hitTest:方法同样接受一个CGPoint类型参数,返回图层本身,或者包含这个坐标点的叶子节点图层。如果这个点在最外面图层的范围之外,则返回nil*/let layer = self.view.layer.hitTest(point)print("touch layer is \(layer)")}

###视觉效果 #####圆角 边框 阴影

// 创建 CALayer
let layer1: CALayer = CALayer()
layer1.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
layer1.backgroundColor = UIColor.red.cgColorlet layer: CALayer = CALayer()
layer.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
layer.backgroundColor = UIColor.blue.cgColor
layer.addSublayer(layer1)
self.view.layer.addSublayer(layer)
// 圆角
layer.cornerRadius = 10
// 边框
layer.borderColor = UIColor.green.cgColor
layer.borderWidth = 3
// maskToBounds属性裁剪掉了阴影和内容
//layer.masksToBounds = true
//阴影效果
//设置图层阴影的偏移量为(w,h)意味着图层的阴影出现在 layer 右侧 w 个点以及下方 h 个点连成的区域上。
layer.shadowOffset = CGSize(width: 10, height: 10)
//将图层阴影的不透明度设为 0.7。这意味着阴影应该是 70% 不透明的。
layer.shadowOpacity = 0.7
/*shadowRadius 将图层阴影的范围设为 5。阴影的范围代表了 layer 所创建的阴影的模糊范围。更高的范围值意味着阴影会更加扩散,但是可视度会降低。较低的范围值使得阴影更加显眼和集中。阴影范围为0会导致根本不会有模糊。换句话说,这使得阴影与图层保持完全相同的尺寸和形状。
*/
layer.shadowRadius = 5
//设置图层阴影的颜色为 CGColor 类型的
layer.shadowColor = UIColor(red: 44.0/255.0, green: 62.0/255.0, blue: 80.0/255.0, alpha: 1.0).cgColor
/*shadowPath是一个CGPathRef类型(一个指向CGPath的指针)。CGPath是一个Core Graphics对象,用来指定任意的一个矢量图形。我们可以通过这个属性单独于图层形状之外指定阴影的形状。如果是一个矩形或者是圆,用CGPath会相当简单明了。但是如果是更加复杂一点的图形,UIBezierPath类会更合适*/
layer.shadowPath = UIBezierPath(rect: layer.bounds).cgPath

#####图层蒙版 mask图层实心的部分会被保留下来,其他的则会被抛弃

// 创建 CALayer
let layer1: CALayer = CALayer()
layer1.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
layer1.contents = UIImage(named: "star")?.cgImagelet layer: CALayer = CALayer()
layer.frame = CGRect(x: 100, y: 100, width: 150, height: 150)
layer.contents = UIImage(named: "bg.jpg")?.cgImage
self.view.layer.addSublayer(layer)/*
mask 将 layer1 与 layer 重叠的layer的部分保留下来,其他的则会被抛弃
*/
layer.mask = layer1

#####拉伸过滤

layer.magnificationFilter // 放大
layer.minificationFilter  // 缩小

CALayer提供了三种拉伸过滤方法

  • kCAFilterLinear
  • kCAFilterNearest
  • kCAFilterTrilinear

minification(缩小图片)和magnification(放大图片)默认的过滤器都是kCAFilterLinear,这个过滤器采用双线性滤波算法,它在大多数情况下都表现良好。双线性滤波算法通过对多个像素取样最终生成新的值,得到一个平滑的表现不错的拉伸。但是当放大倍数比较大的时候图片就模糊不清了。

kCAFilterTrilinear和kCAFilterLinear非常相似,大部分情况下二者都看不出来有什么差别。但是,较双线性滤波算法而言,三线性滤波算法存储了多个大小情况下的图片(也叫多重贴图),并三维取样,同时结合大图和小图的存储进而得到最后的结果。

这个方法的好处在于算法能够从一系列已经接近于最终大小的图片中得到想要的结果,也就是说不要对很多像素同步取样。这不仅提高了性能,也避免了小概率因舍入错误引起的取样失灵的问题

kCAFilterNearest是一种比较武断的方法。从名字不难看出,这个算法(也叫最近过滤)就是取样最近的单像素点而不管其他的颜色。这样做非常快,也不会使图片模糊。但是,最明显的效果就是,会使得压缩图片更糟,图片放大之后也显得块状或是马赛克严重。

总的来说,对于比较小的图或者是差异特别明显,极少斜线的大图,最近过滤算法会保留这种差异明显的特质以呈现更好的结果。但是对于大多数的图尤其是有很多斜线或是曲线轮廓的图片来说,最近过滤算法会导致更差的结果。换句话说,线性过滤保留了形状,最近过滤则保留了像素的差异。

#####透明度 UIView有一个叫做alpha的属性来确定视图的透明度。 CALayer有一个等同的属性叫做opacity, 这两个属性都是影响子层级的。如果你给一个图层设置了opacity属性,那它的子图层都会受此影响。

//透明度
layer.opacity = 0.5
/*
设置CALayer的一个叫做shouldRasterize属性来实现组透明的效果,
如果它被设置为YES,在应用透明度之前,图层及其子图层都会被整合成一个整体的图片,
这样就没有透明度混合的问题了
*/
layer.shouldRasterize = true
/*
默认情况下,所有图层拉伸都是1.0
如果你使用了shouldRasterize属性
你就要确保你设置了rasterizationScale属性去匹配屏幕
以防止出现Retina屏幕像素化的问题
*/
layer.rasterizationScale = UIScreen.main.scale

###变换 #####CGAffineTransform UIView可以通过设置transform属性做变换,但实际上它只是封装了内部图层的变换。 CALayer同样也有一个transform属性affineTransform,但它的类型是CATransform3D,而不是CGAffineTransform

CG的前缀告诉我们,CGAffineTransform类型属于Core Graphics框架,Core Graphics实际上是一个严格意义上的2D绘图API,并且CGAffineTransform仅仅对2D变换有效。

// 旋转 CGFloat.pi = 180度
CGAffineTransform(rotationAngle: CGFloat)
// 缩放
CGAffineTransform(scaleX: CGFloat, y: CGFloat)
// 平移
CGAffineTransform(translationX: CGFloat, y: CGFloat)

Core Graphics提供了一系列的函数可以在一个变换的基础上做更深层次的变换,如:先缩小50%,再旋转30度,最后向右移动100

/* 当操纵一个变换的时候,初始生成一个什么都不做的变换很重要也就是创建一个CGAffineTransform类型的空值,矩阵论中称作单位矩阵
*/
var transform = CGAffineTransform.identity
// 缩小 50%
transform = transform.scaledBy(x: 0.5, y: 0.5)
// 旋转 30度
transform = transform.rotated(by: CGFloat.pi/180*30)
// 平移 100
transform = transform.translatedBy(x: 100, y: 0)
layer.setAffineTransform(transform)

zPosition属性,可以用来让图层靠近或者远离相机(用户视角),transform属性(CATransform3D类型)可以真正做到这点,即让图层在3D空间内移动或者旋转。和CGAffineTransform类似,CATransform3D也是一个矩阵,但是和2x3的矩阵不同,CATransform3D是一个可以在3维空间内做变换的4x4的矩阵

/*
// 旋转
CATransform3DMakeRotation(<#T##angle: CGFloat##CGFloat#>, <#T##x: CGFloat##CGFloat#>, <#T##y: CGFloat##CGFloat#>, <#T##z: CGFloat##CGFloat#>)
// 缩放
CATransform3DMakeScale(<#T##sx: CGFloat##CGFloat#>, <#T##sy: CGFloat##CGFloat#>, <#T##sz: CGFloat##CGFloat#>)
// 平移
CATransform3DMakeTranslation(<#T##tx: CGFloat##CGFloat#>, <#T##ty: CGFloat##CGFloat#>, <#T##tz: CGFloat##CGFloat#>)
*/
// 沿 x 旋转45度 == 原始图片高度的1/2
let transform = CATransform3DMakeRotation(CGFloat.pi/4, 1, 0, 0)
layer.transform = transform

#####CATransform3D CATransform3D的透视效果通过一个矩阵中一个很简单的元素来控制:m34 m34的默认值是0,我们可以通过设置m34为-1.0 / d来应用透视效果,d代表了想象中视角相机和屏幕之间的距离,以像素为单位 一个非常微小的值会让它看起来更加失真,然而一个非常大的值会让它基本失去透视效果

var transform: CATransform3D = CATransform3DIdentity
transform.m34 = -1/500
// 沿 x 旋转45度 == 梯形
transform = CATransform3DRotate(transform, CGFloat.pi/4, 1, 0, 0)
layer.transform = transform

当在透视角度绘图的时候,远离相机视角的物体将会变小变远,当远离到一个极限距离,它们可能就缩成了一个点,于是所有的物体最后都汇聚消失在同一个点。 在现实中,这个点通常是视图的中心,于是为了在应用中创建拟真效果的透视,这个点应该聚在屏幕中点,或者至少是包含所有3D对象的视图中点。 Core Animation定义了这个点位于变换图层的anchorPoint。这就是说,当图层发生变换时,这个点永远位于图层变换之前anchorPoint的位置。

sublayerTransform

// 创建 CALayer
let layer1: CALayer = CALayer()
layer1.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
layer1.contents = UIImage(named: "bg.jpg")?.cgImagelet layer2: CALayer = CALayer()
layer2.frame = CGRect(x: 50, y: 200, width: 100, height: 100)
layer2.contents = UIImage(named: "bg.jpg")?.cgImagelet layer: CALayer = CALayer()
layer.frame = CGRect(x: 20, y: 20, width: 200, height: 400)
layer.addSublayer(layer1)
layer.addSublayer(layer2)
self.view.layer.addSublayer(layer)layer.borderWidth=1
layer1.borderWidth=1
layer2.borderWidth=1/*如果有多个视图或者图层,每个都做3D变换,那就需要分别设置相同的m34值,并且确保在变换之前都在屏幕中央共享同一个position,如果用一个函数封装这些操作的确会更加方便CALayer有一个属性叫做sublayerTransform。CATransform3D类型,影响到所有的子图层。这意味着你可以一次性对包含这些图层的容器做变换,于是所有的子图层都自动继承了这个变换方法。*/
var perspective: CATransform3D = CATransform3DIdentity
perspective.m34 = -1/500
layer.sublayerTransform = perspective//沿 x 旋转-45度 == 梯形(上宽下窄)
let transform1:CATransform3D = CATransform3DMakeRotation(-CGFloat.pi/4, 1, 0, 0)
layer1.transform = transform1//沿 x 旋转45度 == 梯形 是上面的倒影(上窄下宽)
let transform:CATransform3D = CATransform3DMakeRotation(CGFloat.pi/4, 1, 0, 0)
layer2.transform = transform

立方体

//
//  ViewController.swift
//  Demo
//
//  Created by joker on 2016/11/9.
//  Copyright © 2016年 joker. All rights reserved.
//
import UIKit
import GLKitclass ViewController: UIViewController {override func viewDidLoad() {super.viewDidLoad()// 立方体 6 个面let lab1 = UILabel(frame: CGRect(x: 100, y: 100, width: 100, height: 100))let lab2 = UILabel(frame: CGRect(x: 100, y: 100, width: 100, height: 100))let lab3 = UILabel(frame: CGRect(x: 100, y: 100, width: 100, height: 100))let lab4 = UILabel(frame: CGRect(x: 100, y: 100, width: 100, height: 100))let lab5 = UILabel(frame: CGRect(x: 100, y: 100, width: 100, height: 100))let lab6 = UILabel(frame: CGRect(x: 100, y: 100, width: 100, height: 100))lab1.textAlignment = NSTextAlignment.centerlab2.textAlignment = NSTextAlignment.centerlab3.textAlignment = NSTextAlignment.centerlab4.textAlignment = NSTextAlignment.centerlab5.textAlignment = NSTextAlignment.centerlab6.textAlignment = NSTextAlignment.centerlab1.text = "111"lab2.text = "222"lab3.text = "333"lab4.text = "444"lab5.text = "555"lab6.text = "666"lab1.tag = 1lab2.tag = 2lab3.tag = 3lab4.tag = 4lab5.tag = 5lab6.tag = 6lab1.layer.borderWidth=1lab2.layer.borderWidth=1lab3.layer.borderWidth=1lab4.layer.borderWidth=1lab5.layer.borderWidth=1lab6.layer.borderWidth=1self.view.addSubview(lab1)self.view.addSubview(lab2)self.view.addSubview(lab3)self.view.addSubview(lab4)self.view.addSubview(lab5)self.view.addSubview(lab6)// sublayerTransform 所有的子图层都自动继承了这个变换var perspective: CATransform3D = CATransform3DIdentity// 透视效果perspective.m34 = -1.0/500.0// 通过调整容器视图的sublayerTransform去旋转整个立方体perspective = CATransform3DRotate(perspective, -CGFloat.pi/4, 1, 0, 0);perspective = CATransform3DRotate(perspective, -CGFloat.pi/4, 0, 1, 0);self.view.layer.sublayerTransform = perspective// 设置每个面var transform: CATransform3D = CATransform3DMakeTranslation(0, 0, 100)lab1.layer.transform = transformtransform = CATransform3DMakeTranslation(100, 0, 0)transform = CATransform3DRotate(transform, CGFloat.pi/2, 0, 1, 0)lab2.layer.transform = transformtransform = CATransform3DMakeTranslation(0, -100, 0)transform = CATransform3DRotate(transform, CGFloat.pi/2, 1, 0, 0)lab3.layer.transform = transformtransform = CATransform3DMakeTranslation(0, 100, 0)transform = CATransform3DRotate(transform, -CGFloat.pi/2, 1, 0, 0)lab4.layer.transform = transformtransform = CATransform3DMakeTranslation(-100, 0, 0)transform = CATransform3DRotate(transform, -CGFloat.pi/2, 0, 1, 0)lab5.layer.transform = transformtransform = CATransform3DMakeTranslation(0, 0, -100)transform = CATransform3DRotate(transform, CGFloat.pi, 0, 1, 0)lab6.layer.transform = transform//        // 添加阴影
//        applyLighting(face: lab1.layer)
//        applyLighting(face: lab2.layer)
//        applyLighting(face: lab3.layer)
//        applyLighting(face: lab4.layer)
//        applyLighting(face: lab5.layer)
//        applyLighting(face: lab6.layer)}/**如果需要动态地创建光线效果,你可以根据每个视图的方向应用不同的alpha值做出半透明的阴影图层,但为了计算阴影图层的不透明度,你需要得到每个面的正太向量(垂直于表面的向量),然后根据一个想象的光源计算出两个向量叉乘结果。叉乘代表了光源和图层之间的角度,从而决定了它有多大程度上的光亮。我们用GLKit框架来做向量的计算,每个面的CATransform3D都被转换成GLKMatrix4,然后通过GLKMatrix4GetMatrix3函数得出一个3×3的旋转矩阵。这个旋转矩阵指定了图层的方向,然后可以用它来得到正太向量的值。*/func applyLighting(face:CALayer){let layer: CALayer = CALayer()layer.frame = face.boundsface.addSublayer(layer)let transform: CATransform3D = face.transform// 不知道怎么转换// GLKMatrix4 matrix4 = *(GLKMatrix4 *)&transform;let matrix4: GLKMatrix4 = transform as! GLKMatrix4let matrix3: GLKMatrix3 = GLKMatrix4GetMatrix3(matrix4)var normal: GLKVector3 = GLKVector3Make(0, 0, 1)normal = GLKMatrix3MultiplyVector3(matrix3, normal)normal = GLKVector3Normalize(normal)let light: GLKVector3 = GLKVector3Normalize(GLKVector3Make(0, 1, -5))let dotProduct: Float = GLKVector3DotProduct(light, normal)let shadow: CGFloat = 1 + CGFloat(dotProduct) - 0.5let color: UIColor = UIColor(white: 0, alpha: shadow)layer.backgroundColor = color.cgColor}override func didReceiveMemoryWarning() {super.didReceiveMemoryWarning()// Dispose of any resources that can be recreated.}
}

参考资料:https://zsisme.gitbooks.io/ios-/content/index.html

转载于:https://my.oschina.net/asjoker/blog/785839

Core Animation总结(一)图层变换(平面 立体)相关推荐

  1. iOS开发:Core Animation编程指南

    关于Core Animation Core Animation是iOS与OS X平台上负责图形渲染与动画的基础设施.Core Animation可以动画视图和其他的可视元素.Core Animatio ...

  2. 玩转iOS开发:5.《Core Animation》CALayer的Transforms

    文章转至我的个人博客: https://cainluo.github.io/14777052484078.html 作者感言 之前我们所了解的CALayer都是比较抽象化, 好在<Core An ...

  3. Core Animation的使用

    关于Core Animation Core Animation是IOS和OS X的图形渲染和动画的基础设施,你可以使用它来进行动画绘制视图和其他APP的可视元素.Core Animation为你完成大 ...

  4. Core Animation学习总结

    目录: The Layer Beneath The Layer Tree(图层树) The Backing Image(寄宿层) Layer Geometry(图层几何学) Visual Effect ...

  5. 图层几何学 -- iOS Core Animation 系列二

    <图层树和寄宿图 -- iOS Core Animation 系列一>介绍了图层的基础知识和一些属性方法.这篇主要内容是学习下图层在父图层上怎么控制位置和尺寸的. 1.布局 首先看一张例图 ...

  6. iOS Core Animation Advanced Techniques(七):高效绘图、图像IO以及图层性能

    高效绘图 不必要的效率考虑往往是性能问题的万恶之源. --William Allan Wulf 在第12章『速度的曲率』我们学习如何用Instruments来诊断Core Animation性能问题. ...

  7. iOS 核心动画 Core Animation浅谈

    代码地址如下: http://www.demodashi.com/demo/11603.html 前记 关于实现一个iOS动画,如果简单的,我们可以直接调用UIView的代码块来实现,虽然使用UIVi ...

  8. Core Animation 文档翻译 (第二篇)—核心动画基础要素

    前言 核心动画为我们APP内Views动画和其他可视化元素动画提供了综合性的实现体系.核心动画不是我们APP内Views的替代品,相反,它是一种结合Views来提供更好性能和支持Content动画的技 ...

  9. [译]Core Animation 3D介绍(第2部分)

    尊重原创 转自:http://codingobjc.com/blog/2013/06/24/core-animation-3djie-shao-di-2bu-fen/ 在上一篇教程中,我们已经学习了C ...

最新文章

  1. 少走弯路的10条忠告
  2. auot lisp 选择集处理_第64集 python机器学习:用预处理进行参数选择
  3. 微软热门知识点之------c#3.0新特性【转】
  4. 分不清的InputStream和OutputStream
  5. SSL *** 安全解决方案
  6. 【LeetCode笔记】剑指 Offer 44. 数字序列中某一位的数字(Java、偏数学)
  7. asf linux教程,ASF V3.0 windows/linux含树莓派部署流程
  8. Google Adwords/SEO关键字策略之Google Webmaster Tool数据方法
  9. 以小见大:如何设计注册登录页?
  10. leetcode 题解 java_leetcode-java题解(每天更新)
  11. Python学习-生成器
  12. 自动化测试平台(七):头像展示、下拉菜单及用户管理模块增删改功能实现
  13. 用计算机就行DNA翻译的程序,南邮通达科技英语原文翻译Lession 2 CTEXT
  14. python中的MRO
  15. python程序格式框架的描述错误的是_关于 Python 程序格式框架的描述,以下选项中错误的是(       )...
  16. uniapp开发微信小程序教程(一)
  17. 一个班37人考进清华北大,老师发来一则短信,家长都沉默了!
  18. centos下php的mysqli扩展安装
  19. java面试英语自我介绍_【埃森哲java工程师面试】就是简单英文自我介绍。-看准网...
  20. 我对社交电商的了解与看法

热门文章

  1. abaqus的三维几何体建模插件(线条/圆柱/椭球/球体)--Abaqus Geometry 2.0
  2. Java:学校比赛现场有10个评委,要求从键盘输入10个分数作为评委对一名选手的打分,评分规则为去掉一个最高分,去掉一个最低分,求该名选手平均分,打印到控制台。
  3. 脑机接口科普0014——大脑
  4. 如何确定数组中含有某个元素?
  5. mysql节假日判定_是否是工作日和节假日判定
  6. android 游戏 锁屏界面开发,android 锁屏程序开发
  7. 【Maven基础】单一架构案例(一)
  8. 十行代码带你量化交易入门
  9. PHP查询MYSQL数据库
  10. php 串口通讯,PHP使用RS232串口通讯传送文件的应用演示