diff --git "a/1-\345\233\276\345\261\202\346\240\221/\345\233\276\345\261\202\346\240\221.md" "b/1-\345\233\276\345\261\202\346\240\221/\345\233\276\345\261\202\346\240\221.md"
index 76dae76..d4cbf8e 100644
--- "a/1-\345\233\276\345\261\202\346\240\221/\345\233\276\345\261\202\346\240\221.md"
+++ "b/1-\345\233\276\345\261\202\346\240\221/\345\233\276\345\261\202\346\240\221.md"
@@ -1,4 +1,4 @@
-#图层的树状结构
+# 图层的树状结构
>巨妖有图层,洋葱也有图层,你懂吗?我们都有图层 -- 史莱克
@@ -8,7 +8,7 @@ Core Animation是一个*复合引擎*,它的职责就是尽可能快地组合
在我们讨论动画之前,我们将从图层树开始,涉及一下Core Animation的*静态*组合以及布局特性。
-##图层和视图
+## 图层和视图
如果你曾经在iOS或者Mac OS平台上写过应用程序,你可能会对*视图*的概念比较熟悉。一个视图就是在屏幕上显示的一个矩形块(比如图片,文字或者视频),它能够拦截类似于鼠标点击或者触摸手势等用户输入。视图在层级关系中可以互相嵌套,一个视图可以管理它的所有子视图的位置。图1.1显示了一种典型的视图层级关系
@@ -17,12 +17,12 @@ Core Animation是一个*复合引擎*,它的职责就是尽可能快地组合
在iOS当中,所有的视图都从一个叫做`UIVIew`的基类派生而来,`UIView`可以处理触摸事件,可以支持基于*Core Graphics*绘图,可以做仿射变换(例如旋转或者缩放),或者简单的类似于滑动或者渐变的动画。
-###CALayer
+### CALayer
`CALayer`类在概念上和`UIView`类似,同样也是一些被层级关系树管理的矩形块,同样也可以包含一些内容(像图片,文本或者背景色),管理子图层的位置。它们有一些方法和属性用来做动画和变换。和`UIView`最大的不同是`CALayer`不处理用户的交互。
`CALayer`并不清楚具体的*响应链*(iOS通过视图层级关系用来传送触摸事件的机制),于是它并不能够响应事件,即使它提供了一些方法来判断是否一个触点在图层的范围之内(具体见第三章,“图层的几何学”)
-###平行的层级关系
+### 平行的层级关系
每一个`UIview`都有一个`CALayer`实例的图层属性,也就是所谓的*backing layer*,视图的职责就是创建并管理这个图层,以确保当子视图在层级关系中添加或者被移除的时候,他们关联的图层也同样对应在层级关系树当中有相同的操作(见图1.2)。
@@ -54,7 +54,7 @@ Core Animation是一个*复合引擎*,它的职责就是尽可能快地组合
我们将会在后续章节中探索这些功能,首先我们要关注一下在应用程序当中`CALayer`是怎样被利用起来的。
-##使用图层
+## 使用图层
首先我们来创建一个简单的项目,来操纵一些`layer`的属性。打开Xcode,使用*Single View Application*模板创建一个工程。
在屏幕中央创建一个小视图(大约200 X 200的尺寸),当然你可以手工编码,或者使用Interface Builder(随你方便)。确保你的视图控制器要添加一个视图的属性以便可以直接访问它。我们把它称作`layerView`。
@@ -120,7 +120,7 @@ Core Animation是一个*复合引擎*,它的职责就是尽可能快地组合
但是这些例子都很少见,总的来说,处理视图会比单独处理图层更加方便。
-##总结
+## 总结
这一章阐述了图层的树状结构,说明了如何在iOS中由`UIView`的层级关系形成的一种平行的`CALayer`层级关系,在后面的实验中,我们创建了自己的`CALayer`,并把它添加到图层树中。
在第二章,“图层关联的图片”,我们将要研究一下`CALayer`关联的图片,以及Core Animation提供的操作显示的一些特性。
diff --git "a/10-\347\274\223\345\206\262/\347\274\223\345\206\262.md" "b/10-\347\274\223\345\206\262/\347\274\223\345\206\262.md"
index 6200678..b2c096f 100644
--- "a/10-\347\274\223\345\206\262/\347\274\223\345\206\262.md"
+++ "b/10-\347\274\223\345\206\262/\347\274\223\345\206\262.md"
@@ -1,10 +1,10 @@
-#缓冲
+# 缓冲
>生活和艺术一样,最美的永远是曲线。 -- 爱德华布尔沃 - 利顿
在第九章“图层时间”中,我们讨论了动画时间和`CAMediaTiming`协议。现在我们来看一下另一个和时间相关的机制--所谓的*缓冲*。Core Animation使用缓冲来使动画移动更平滑更自然,而不是看起来的那种机械和人工,在这一章我们将要研究如何对你的动画控制和自定义缓冲曲线。
-##动画速度
+## 动画速度
动画实际上就是一段时间内的变化,这就暗示了变化一定是随着某个特定的速率进行。速率由以下公式计算而来:
@@ -20,7 +20,7 @@
现实生活中的任何一个物体都会在运动中加速或者减速。那么我们如何在动画中实现这种加速度呢?一种方法是使用*物理引擎*来对运动物体的摩擦和动量来建模,然而这会使得计算过于复杂。我们称这种类型的方程为*缓冲函数*,幸运的是,Core Animation内嵌了一系列标准函数提供给我们使用。
-###`CAMediaTimingFunction`
+### `CAMediaTimingFunction`
那么该如何使用缓冲方程式呢?首先需要设置`CAAnimation`的`timingFunction`属性,是`CAMediaTimingFunction`类的一个对象。如果想改变隐式动画的计时函数,同样也可以使用`CATransaction`的`+setAnimationTimingFunction:`方法。
@@ -81,7 +81,7 @@
@end
```
-###`UIView`的动画缓冲
+### `UIView`的动画缓冲
UIKit的动画也同样支持这些缓冲方法的使用,尽管语法和常量有些不同,为了改变`UIView`动画的缓冲选项,给`options`参数添加如下常量之一:
@@ -132,7 +132,7 @@ UIKit的动画也同样支持这些缓冲方法的使用,尽管语法和常量
@end
```
-###缓冲和关键帧动画
+### 缓冲和关键帧动画
或许你会回想起第八章里面颜色切换的关键帧动画由于线性变换的原因(见清单8.5)看起来有些奇怪,使得颜色变换非常不自然。为了纠正这点,我们来用更加合适的缓冲方法,例如`kCAMediaTimingFunctionEaseIn`,给图层的颜色变化添加一点*脉冲*效果,让它更像现实中的一个彩色灯泡。
@@ -188,7 +188,7 @@ UIKit的动画也同样支持这些缓冲方法的使用,尽管语法和常量
@end
```
-##自定义缓冲函数
+## 自定义缓冲函数
在第八章中,我们给时钟项目添加了动画。看起来很赞,但是如果有合适的缓冲函数就更好了。在现实世界中,钟表指针转动的时候,通常起步很慢,然后迅速啪地一声,最后缓冲到终点。但是标准的缓冲函数在这里没一个适合它,那该如何创建一个新的呢?
@@ -196,7 +196,7 @@ UIKit的动画也同样支持这些缓冲方法的使用,尽管语法和常量
使用这个方法,我们可以创建一个自定义的缓冲函数,来匹配我们的时钟动画,为了理解如何使用这个方法,我们要了解一些`CAMediaTimingFunction`是如何工作的。
-###三次贝塞尔曲线
+### 三次贝塞尔曲线
`CAMediaTimingFunction`函数的主要原则在于它把输入的时间转换成起点和终点之间成比例的改变。我们可以用一个简单的图标来解释,横轴代表时间,纵轴代表改变的量,于是线性的缓冲就是一条从起点开始的简单的斜线(图10.1)。
@@ -301,7 +301,7 @@ UIKit的动画也同样支持这些缓冲方法的使用,尽管语法和常量
}
```
-###更加复杂的动画曲线
+### 更加复杂的动画曲线
考虑一个橡胶球掉落到坚硬的地面的场景,当开始下落的时候,它会持续加速知道落到地面,然后经过几次反弹,最后停下来。如果用一张图来说明,它会如图10.5所示。
@@ -314,7 +314,7 @@ UIKit的动画也同样支持这些缓冲方法的使用,尽管语法和常量
* 用`CAKeyframeAnimation`创建一个动画,然后分割成几个步骤,每个小步骤使用自己的计时函数(具体下节介绍)。
* 使用定时器逐帧更新实现动画(见第11章,“基于定时器的动画”)。
-###基于关键帧的缓冲
+### 基于关键帧的缓冲
为了使用关键帧实现反弹动画,我们需要在缓冲曲线中对每一个显著的点创建一个关键帧(在这个情况下,关键点也就是每次反弹的峰值),然后应用缓冲函数把每段曲线连接起来。同时,我们也需要通过`keyTimes`来指定每个关键帧的时间偏移,由于每次反弹的时间都会减少,于是关键帧并不会均匀分布。
@@ -394,7 +394,7 @@ UIKit的动画也同样支持这些缓冲方法的使用,尽管语法和常量
这种方式还算不错,但是实现起来略显笨重(因为要不停地尝试计算各种关键帧和时间偏移)并且和动画强绑定了(因为如果要改变动画的一个属性,那就意味着要重新计算所有的关键帧)。那该如何写一个方法,用缓冲函数来把任何简单的属性动画转换成关键帧动画呢,下面我们来实现它。
-###流程自动化
+### 流程自动化
在清单10.6中,我们把动画分割成相当大的几块,然后用Core Animation的缓冲进入和缓冲退出函数来大约形成我们想要的曲线。但如果我们把动画分割成更小的几部分,那么我们就可以用直线来拼接这些曲线(也就是线性缓冲)。为了实现自动化,我们需要知道如何做如下两件事情:
@@ -523,7 +523,7 @@ float bounceEaseOut(float t)
}
```
-##总结
+## 总结
在这一章中,我们了解了有关缓冲和`CAMediaTimingFunction`类,它可以允许我们创建自定义的缓冲函数来完善我们的动画,同样了解了如何用`CAKeyframeAnimation`来避开`CAMediaTimingFunction`的限制,创建完全自定义的缓冲函数。
在下一章中,我们将要研究基于定时器的动画--另一个给我们对动画更多控制的选择,并且实现对动画的实时操纵。
diff --git "a/11-\345\237\272\344\272\216\345\256\232\346\227\266\345\231\250\347\232\204\345\212\250\347\224\273/\345\237\272\344\272\216\345\256\232\346\227\266\345\231\250\347\232\204\345\212\250\347\224\273.md" "b/11-\345\237\272\344\272\216\345\256\232\346\227\266\345\231\250\347\232\204\345\212\250\347\224\273/\345\237\272\344\272\216\345\256\232\346\227\266\345\231\250\347\232\204\345\212\250\347\224\273.md"
index 0ec4558..bf60fbc 100644
--- "a/11-\345\237\272\344\272\216\345\256\232\346\227\266\345\231\250\347\232\204\345\212\250\347\224\273/\345\237\272\344\272\216\345\256\232\346\227\266\345\231\250\347\232\204\345\212\250\347\224\273.md"
+++ "b/11-\345\237\272\344\272\216\345\256\232\346\227\266\345\231\250\347\232\204\345\212\250\347\224\273/\345\237\272\344\272\216\345\256\232\346\227\266\345\231\250\347\232\204\345\212\250\347\224\273.md"
@@ -1,10 +1,10 @@
-#基于定时器的动画
+# 基于定时器的动画
> *我可以指导你,但是你必须按照我说的做。* -- 骇客帝国
在第10章“缓冲”中,我们研究了`CAMediaTimingFunction`,它是一个通过控制动画缓冲来模拟物理效果例如加速或者减速来增强现实感的东西,那么如果想更加真实地模拟物理交互或者实时根据用户输入修改动画改怎么办呢?在这一章中,我们将继续探索一种能够允许我们精确地控制一帧一帧展示的基于定时器的动画。
-##定时帧
+## 定时帧
动画看起来是用来显示一段连续的运动过程,但实际上当在固定位置上展示像素的时候并不能做到这一点。一般来说这种显示都无法做到连续的移动,能做的仅仅是足够快地展示一系列静态图片,只是看起来像是做了运动。
@@ -12,7 +12,7 @@
在第10章中,我们解决了如何自定义缓冲函数,然后根据需要展示的帧的数组来告诉`CAKeyframeAnimation`的实例如何去绘制。所有的Core Animation实际上都是按照一定的序列来显示这些帧,那么我们可以自己做到这些么?
-###`NSTimer`
+### `NSTimer`
实际上,我们在第三章“图层几何学”中已经做过类似的东西,就是时钟那个例子,我们用了`NSTimer`来对钟表的指针做定时动画,一秒钟更新一次,但是如果我们把频率调整成一秒钟更新60次的话,原理是完全相同的。
@@ -91,13 +91,13 @@
* 基于真实帧的持续时间而不是假设的更新频率来做动画。
* 调整动画计时器的`run loop`模式,这样就不会被别的事件干扰。
-###`CADisplayLink`
+### `CADisplayLink`
`CADisplayLink`是CoreAnimation提供的另一个类似于`NSTimer`的类,它总是在屏幕完成一次更新之前启动,它的接口设计的和`NSTimer`很类似,所以它实际上就是一个内置实现的替代,但是和`timeInterval`以秒为单位不同,`CADisplayLink`有一个整型的`frameInterval`属性,指定了间隔多少帧之后才执行。默认值是1,意味着每次屏幕更新之前都会执行一次。但是如果动画的代码执行起来超过了六十分之一秒,你可以指定`frameInterval`为2,就是说动画每隔一帧执行一次(一秒钟30帧)或者3,也就是一秒钟20次,等等。
用`CADisplayLink`而不是`NSTimer`,会保证帧率足够连续,使得动画看起来更加平滑,但即使`CADisplayLink`也不能*保证*每一帧都按计划执行,一些失去控制的离散的任务或者事件(例如资源紧张的后台程序)可能会导致动画偶尔地丢帧。当使用`NSTimer`的时候,一旦有机会计时器就会开启,但是`CADisplayLink`却不一样:如果它丢失了帧,就会直接忽略它们,然后在下一次更新的时候接着运行。
-###计算帧的持续时间
+### 计算帧的持续时间
无论是使用`NSTimer`还是`CADisplayLink`,我们仍然需要处理一帧的时间超出了预期的六十分之一秒。由于我们不能够计算出一帧真实的持续时间,所以需要手动测量。我们可以在每帧开始刷新的时候用`CACurrentMediaTime()`记录当前时间,然后和上一帧记录的时间去比较。
@@ -134,7 +134,7 @@
@end
```
-###Run Loop 模式
+### Run Loop 模式
注意到当创建`CADisplayLink`的时候,我们需要指定一个`run loop`和`run loop mode`,对于run loop来说,我们就使用了主线程的run loop,因为任何用户界面的更新都需要在主线程执行,但是模式的选择就并不那么清楚了,每个添加到run loop的任务都有一个指定了优先级的模式,为了保证用户界面保持平滑,iOS会提供和用户界面相关任务的优先级,而且当UI很活跃的时候的确会暂停一些别的任务。
一个典型的例子就是当是用`UIScrollview`滑动的时候,重绘滚动视图的内容会比别的任务优先级更高,所以标准的`NSTimer`和网络请求就不会启动,一些常见的run loop模式如下:
@@ -154,11 +154,11 @@
[[NSRunLoop mainRunLoop] addTimer:self.timer
forMode:NSRunLoopCommonModes];
-##物理模拟
+## 物理模拟
即使使用了基于定时器的动画来复制第10章中关键帧的行为,但还是会有一些本质上的区别:在关键帧的实现中,我们提前计算了所有帧,但是在新的解决方案中,我们实际上实在按需要在计算。意义在于我们可以根据用户输入实时修改动画的逻辑,或者和别的实时动画系统例如物理引擎进行整合。
-###Chipmunk
+### Chipmunk
我们来基于物理学创建一个真实的重力模拟效果来取代当前基于缓冲的弹性动画,但即使模拟2D的物理效果就已近极其复杂了,所以就不要尝试去实现它了,直接用开源的物理引擎库好了。
@@ -224,7 +224,7 @@
图11.1 一个木箱图片,根据模拟的重力掉落
-
###添加用户交互
+
### 添加用户交互
下一步就是在视图周围添加一道不可见的墙,这样木箱就不会掉落出屏幕之外。或许你会用另一个矩形的`cpPolyShape`来实现,就和之前创建木箱那样,但是我们需要检测的是木箱何时离开视图,而不是何时碰撞,所以我们需要一个空心而不是固体矩形。
我们可以通过给`cpSpace`添加四个`cpSegmentShape`对象(`cpSegmentShape`代表一条直线,所以四个拼起来就是一个矩形)。然后赋给空间的`staticBody`属性(一个不被重力影响的结构体)而不是像木箱那样一个新的`cpBody`实例,因为我们不想让这个边框矩形滑出屏幕或者被一个下落的木箱击中而消失。
同样可以再添加一些木箱来做一些交互。最后再添加一个加速器,这样可以通过倾斜手机来调整重力矢量(为了测试需要在一台真实的设备上运行程序,因为模拟器不支持加速器事件,即使旋转屏幕)。清单11.4展示了更新后的代码,运行结果见图11.2。
@@ -254,7 +254,7 @@
}
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
//update gravity
cpSpaceSetGravity(self.space, cpv(acceleration.y * GRAVITY, -acceleration.x * GRAVITY));
}
```
图11.1 真实引力场下的木箱交互
-
###模拟时间以及固定的时间步长
+
### 模拟时间以及固定的时间步长
对于实现动画的缓冲效果来说,计算每帧持续的时间是一个很好的解决方案,但是对模拟物理效果并不理想。通过一个可变的时间步长来实现有着两个弊端:
* 如果时间步长不是固定的,精确的值,物理效果的模拟也就随之不确定。这意味着即使是传入相同的输入值,也可能在不同场合下有着不同的效果。有时候没多大影响,但是在基于物理引擎的游戏下,玩家就会由于相同的操作行为导致不同的结果而感到困惑。同样也会让测试变得麻烦。
* 由于性能故常造成的丢帧或者像电话呼入的中断都可能会造成不正确的结果。考虑一个像子弹那样快速移动物体,每一帧的更新都需要移动子弹,检测碰撞。如果两帧之间的时间加长了,子弹就会在这一步移动更远的距离,穿过围墙或者是别的障碍,这样就丢失了碰撞。
@@ -268,9 +268,9 @@
{
//calculate frame step duration
CFTimeInterval frameTime = CACurrentMediaTime();
//update simulation
while (self.lastStep < frameTime) {
cpSpaceStep(self.space, SIMULATION_STEP);
self.lastStep += SIMULATION_STEP;
}

//update all the shapes
cpSpaceEachShape(self.space, &updateShape, NULL);
-}
```
###避免死亡螺旋
+}
```
### 避免死亡螺旋
当使用固定的模拟时间步长时候,有一件事情一定要注意,就是用来计算物理效果的现实世界的时间并不会加速模拟时间步长。在我们的例子中,我们随意选择了120分之一秒来模拟物理效果。Chipmunk很快,我们的例子也很简单,所以`cpSpaceStep()`会完成的很好,不会延迟帧的更新。
但是如果场景很复杂,比如有上百个物体之间的交互,物理计算就会很复杂,`cpSpaceStep()`的计算也可能会超出1/120秒。我们没有测量出物理步长的时间,因为我们假设了相对于帧刷新来说并不重要,但是如果模拟步长更久的话,就会延迟帧率。
-如果帧刷新的时间延迟的话会变得很糟糕,我们的模拟需要执行更多的次数来同步真实的时间。这些额外的步骤就会继续延迟帧的更新,等等。这就是所谓的死亡螺旋,因为最后的结果就是帧率变得越来越慢,直到最后应用程序卡死了。
我们可以通过添加一些代码在设备上来对物理步骤计算真实世界的时间,然后自动调整固定时间步长,但是实际上它不可行。其实只要保证你给容错留下足够的边长,然后在期望支持的最慢的设备上进行测试就可以了。如果物理计算超过了模拟时间的50%,就需要考虑增加模拟时间步长(或者简化场景)。如果模拟时间步长增加到超过1/60秒(一个完整的屏幕更新时间),你就需要减少动画帧率到一秒30帧或者增加`CADisplayLink`的`frameInterval`来保证不会随机丢帧,不然你的动画将会看起来不平滑。
##总结
+如果帧刷新的时间延迟的话会变得很糟糕,我们的模拟需要执行更多的次数来同步真实的时间。这些额外的步骤就会继续延迟帧的更新,等等。这就是所谓的死亡螺旋,因为最后的结果就是帧率变得越来越慢,直到最后应用程序卡死了。
我们可以通过添加一些代码在设备上来对物理步骤计算真实世界的时间,然后自动调整固定时间步长,但是实际上它不可行。其实只要保证你给容错留下足够的边长,然后在期望支持的最慢的设备上进行测试就可以了。如果物理计算超过了模拟时间的50%,就需要考虑增加模拟时间步长(或者简化场景)。如果模拟时间步长增加到超过1/60秒(一个完整的屏幕更新时间),你就需要减少动画帧率到一秒30帧或者增加`CADisplayLink`的`frameInterval`来保证不会随机丢帧,不然你的动画将会看起来不平滑。
## 总结
在这一章中,我们了解了如何通过一个计时器创建一帧帧的实时动画,包括缓冲,物理模拟等等一系列动画技术,以及用户输入(通过加速计)。
在第三部分中,我们将研究动画性能是如何被被设备限制所影响的,以及如何调整我们的代码来活的足够好的帧率。
diff --git "a/12-\346\200\247\350\203\275\350\260\203\344\274\230/\346\200\247\350\203\275\350\260\203\344\274\230.md" "b/12-\346\200\247\350\203\275\350\260\203\344\274\230/\346\200\247\350\203\275\350\260\203\344\274\230.md"
index cd2c2a5..5651c90 100644
--- "a/12-\346\200\247\350\203\275\350\260\203\344\274\230/\346\200\247\350\203\275\350\260\203\344\274\230.md"
+++ "b/12-\346\200\247\350\203\275\350\260\203\344\274\230/\346\200\247\350\203\275\350\260\203\344\274\230.md"
@@ -1,10 +1,10 @@
-#性能调优
+# 性能调优
>*代码应该运行的尽量快,而不是更快* - 理查德
在第一和第二部分,我们了解了Core Animation提供的关于绘制和动画的一些特性。Core Animation功能和性能都非常强大,但如果你对背后的原理不清楚的话也会降低效率。让它达到最优的状态是一门艺术。在这章中,我们将探究一些动画运行慢的原因,以及如何去修复这些问题。
-##CPU VS GPU
+## CPU VS GPU
关于绘图和动画有两种处理的方式:CPU(中央处理器)和GPU(图形处理器)。在现代iOS设备中,都有可以运行不同软件的可编程芯片,但是由于历史原因,我们可以说CPU所做的工作都在软件层面,而GPU在硬件层面。
@@ -12,7 +12,7 @@
大多数动画性能优化都是关于智能利用GPU和CPU,使得它们都不会超出负荷。于是我们首先需要知道Core Animation是如何在这两个处理器之间分配工作的。
-###动画的舞台
+### 动画的舞台
Core Animation处在iOS的核心地位:应用内和应用间都会用到它。一个简单的动画可能同步显示多个app的内容,例如当在iPad上多个程序之间使用手势切换,会使得多个程序同时显示在屏幕上。在一个特定的应用中用代码实现它是没有意义的,因为在iOS中不可能实现这种效果(App都是被沙箱管理,不能访问别的视图)。
@@ -38,7 +38,7 @@ Core Animation处在iOS的核心地位:应用内和应用间都会用到它。
这并不是个问题,因为在布局和显示阶段,你可以决定哪些由CPU执行,哪些交给GPU去做。那么改如何判断呢?
-###GPU相关的操作
+### GPU相关的操作
GPU为一个具体的任务做了优化:它用来采集图片和形状(三角形),运行变换,应用纹理和混合然后把它们输送到屏幕上。现代iOS设备上可编程的GPU在这些操作的执行上又很大的灵活性,但是Core Animation并没有暴露出直接的接口。除非你想绕开Core Animation并编写你自己的OpenGL着色器,从根本上解决硬件加速的问题,那么剩下的所有都还是需要在CPU的软件层面上完成。
@@ -54,7 +54,7 @@ GPU为一个具体的任务做了优化:它用来采集图片和形状(三
* 过大的图片 - 如果视图绘制超出GPU支持的2048x2048或者4096x4096尺寸的纹理,就必须要用CPU在图层每次显示之前对图片预处理,同样也会降低性能。
-###CPU相关的操作
+### CPU相关的操作
大多数工作在Core Animation的CPU都发生在动画开始之前。这意味着它不会影响到帧率,所以很好,但是他会延迟动画开始的时间,让你的界面看起来会比较迟钝。
@@ -70,13 +70,13 @@ GPU为一个具体的任务做了优化:它用来采集图片和形状(三
当图层被成功打包,发送到渲染服务器之后,CPU仍然要做如下工作:为了显示屏幕上的图层,Core Animation必须对渲染树种的每个可见图层通过OpenGL循环转换成纹理三角板。由于GPU并不知晓Core Animation图层的任何结构,所以必须要由CPU做这些事情。这里CPU涉及的工作和图层个数成正比,所以如果在你的层级关系中有太多的图层,就会导致CPU每一帧的渲染,即使这些事情不是你的应用程序可控的。
-###IO相关操作
+### IO相关操作
还有一项没涉及的就是IO相关工作。上下文中的IO(输入/输出)指的是例如闪存或者网络接口的硬件访问。一些动画可能需要从山村(甚至是远程URL)来加载。一个典型的例子就是两个视图控制器之间的过渡效果,这就需要从一个nib文件或者是它的内容中懒加载,或者一个旋转的图片,可能在内存中尺寸太大,需要动态滚动来加载。
IO比内存访问更慢,所以如果动画涉及到IO,就是一个大问题。总的来说,这就需要使用聪敏但尴尬的技术,也就是多线程,缓存和投机加载(提前加载当前不需要的资源,但是之后可能需要用到)。这些技术将会在第14章中讨论。
-##测量,而不是猜测
+## 测量,而不是猜测
于是现在你知道有哪些点可能会影响动画性能,那该如何修复呢?好吧,其实不需要。有很多种诡计来优化动画,但如果盲目使用的话,可能会造成更多性能上的问题,而不是修复。
@@ -84,7 +84,7 @@ IO比内存访问更慢,所以如果动画涉及到IO,就是一个大问题
那该如何测量呢?第一步就是确保在真实环境下测试你的程序。
-###真机测试,而不是模拟器
+### 真机测试,而不是模拟器
当你开始做一些性能方面的工作时,一定要在真机上测试,而不是模拟器。模拟器虽然是加快开发效率的一把利器,但它不能提供准确的真机性能参数。
@@ -96,7 +96,7 @@ IO比内存访问更慢,所以如果动画涉及到IO,就是一个大问题
最后,最好在你支持的设备中性能最差的设备上测试:如果基于iOS6开发,这意味着最好在iPhone 3GS或者iPad2上测试。如果可能的话,测试不同的设备和iOS版本,因为苹果在不同的iOS版本和设备中做了一些改变,这也可能影响到一些性能。例如iPad3明显要在动画渲染上比iPad2慢很多,因为渲染4倍多的像素点(为了支持视网膜显示)。
-###保持一致的帧率
+### 保持一致的帧率
为了做到动画的平滑,你需要以60FPS(帧每秒)的速度运行,以同步屏幕刷新速率。通过基于`NSTimer`或者`CADisplayLink`的动画你可以降低到30FPS,而且效果还不错,但是没办法通过Core Animation做到这点。如果不保持60FPS的速率,就可能随机丢帧,影响到体验。
@@ -104,7 +104,7 @@ IO比内存访问更慢,所以如果动画涉及到IO,就是一个大问题
你可以在程序中用`CADisplayLink`来测量帧率(就像11章“基于定时器的动画”中那样),然后在屏幕上显示出来,但应用内的FPS显示并不能够完全真实测量出Core Animation性能,因为它仅仅测出应用内的帧率。我们知道很多动画都在应用之外发生(在渲染服务器进程中处理),但同时应用内FPS计数的确可以对某些性能问题提供参考,一旦找出一个问题的地方,你就需要得到更多精确详细的数据来定位到问题所在。苹果提供了一个强大的*Instruments*工具集来帮我们做到这些。
-##Instruments
+## Instruments
Instruments是Xcode套件中没有被充分利用的一个工具。很多iOS开发者从没用过Instruments,或者只是用Leaks工具检测循环引用。实际上有很多Instruments工具,包括为动画性能调优的东西。
@@ -148,7 +148,7 @@ Instruments的一个很棒的功能在于它可以创建我们自定义的工具
* 只显示Obj-C代码 - 隐藏除了Objective-C之外的所有代码。大多数内部的Core Animation代码都是用C或者C++函数,所以这对我们集中精力到我们代码中显式调用的方法就很有用。
-###Core Animation
+### Core Animation
Core Animation工具用来监测Core Animation性能。它给我们提供了周期性的FPS,并且考虑到了发生在程序之外的动画(见图12.4)。
@@ -180,7 +180,7 @@ Core Animation工具也提供了一系列复选框选项来帮助调试渲染瓶
图12.5 iOS模拟器中Core Animation可视化调试选项
-###OpenGL ES驱动
+### OpenGL ES驱动
OpenGL ES驱动工具可以帮你测量GPU的利用率,同样也是一个很好的来判断和GPU相关动画性能的指示器。它同样也提供了类似Core Animation那样显示FPS的工具(图12.6)。
@@ -195,7 +195,7 @@ OpenGL ES驱动工具可以帮你测量GPU的利用率,同样也是一个很
* **Tiler Utilization** - 如果这个值超过了~50%,就意味着你的动画可能限制于几何结构方面,也就是在屏幕上有太多的图层占用了。
-##一个可用的案例
+## 一个可用的案例
现在我们已经对Instruments中动画性能工具非常熟悉了,那么可以用它在现实中解决一些实际问题。
@@ -349,7 +349,7 @@ OpenGL ES驱动工具可以帮你测量GPU的利用率,同样也是一个很
所以我们最初的设想是错的。图片的加载并不是真正的瓶颈所在,而且试图把它置于一个复杂的多线程加载和缓存的实现都将是徒劳。所以在动手修复之前验证问题所在是个很好的习惯!
-##总结
+## 总结
在这章中,我们学习了Core Animation是如何渲染,以及我们可能出现的瓶颈所在。你同样学习了如何使用Instruments来检测和修复性能问题。
diff --git "a/13-\351\253\230\346\225\210\347\273\230\345\233\276/13-\351\253\230\346\225\210\347\273\230\345\233\276.md" "b/13-\351\253\230\346\225\210\347\273\230\345\233\276/13-\351\253\230\346\225\210\347\273\230\345\233\276.md"
index 603562a..ecf22ee 100644
--- "a/13-\351\253\230\346\225\210\347\273\230\345\233\276/13-\351\253\230\346\225\210\347\273\230\345\233\276.md"
+++ "b/13-\351\253\230\346\225\210\347\273\230\345\233\276/13-\351\253\230\346\225\210\347\273\230\345\233\276.md"
@@ -1,11 +1,11 @@
-#高效绘图
+# 高效绘图
> 不必要的效率考虑往往是性能问题的万恶之源。
> ——William Allan Wulf
在第12章『速度的曲率』我们学习如何用Instruments来诊断Core Animation性能问题。在构建一个iOS app的时候会遇到很多潜在的性能陷阱,但是在本章我们将着眼于有关*绘制*的性能问题。
-##软件绘图
+## 软件绘图
术语*绘图*通常在Core Animation的上下文中指代软件绘图(意即:不由GPU协助的绘图)。在iOS中,软件绘图通常是由Core Graphics框架完成来完成。但是,在一些必要的情况下,相比Core Animation和OpenGL,Core Graphics要慢了不少。
@@ -15,7 +15,7 @@
软件绘图的代价昂贵,除非绝对必要,你应该避免重绘你的视图。提高绘制性能的秘诀就在于尽量避免去绘制。
-##矢量图形
+## 矢量图形
我们用Core Graphics来绘图的一个通常原因就是只是用图片或是图层效果不能轻易地绘制出矢量图形。矢量绘图包含一下这些:
@@ -148,7 +148,7 @@ Core Animation为这些图形类型的绘制提供了专门的类,并给他们
@end
```
-##脏矩形
+## 脏矩形
有时候用`CAShapeLayer`或者其他矢量图形图层替代Core Graphics并不是那么切实可行。比如我们的绘图应用:我们用线条完美地完成了矢量绘制。但是设想一下如果我们能进一步提高应用的性能,让它就像一个黑板一样工作,然后用『粉笔』来绘制线条。模拟粉笔最简单的方法就是用一个『线刷』图片然后将它粘贴到用户手指碰触的地方,但是这个方法用`CAShapeLayer`没办法实现。
@@ -284,17 +284,17 @@ Core Animation为这些图形类型的绘制提供了专门的类,并给他们
图13.4 更好的帧率和顺滑线条
-##异步绘制
+## 异步绘制
UIKit的单线程天性意味着寄宿图通常要在主线程上更新,这意味着绘制会打断用户交互,甚至让整个app看起来处于无响应状态。我们对此无能为力,但是如果能避免用户等待绘制完成就好多了。
针对这个问题,有一些方法可以用到:一些情况下,我们可以推测性地提前在另外一个线程上绘制内容,然后将由此绘出的图片直接设置为图层的内容。这实现起来可能不是很方便,但是在特定情况下是可行的。Core Animation提供了一些选择:`CATiledLayer`和`drawsAsynchronously`属性。
-###CATiledLayer
+### CATiledLayer
我们在第六章简单探索了一下`CATiledLayer`。除了将图层再次分割成独立更新的小块(类似于脏矩形自动更新的概念),`CATiledLayer`还有一个有趣的特性:在多个线程中为每个小块同时调用`-drawLayer:inContext:`方法。这就避免了阻塞用户交互而且能够利用多核心新片来更快地绘制。只有一个小块的`CATiledLayer`是实现异步更新图片视图的简单方法。
-###drawsAsynchronously
+### drawsAsynchronously
iOS 6中,苹果为`CALayer`引入了这个令人好奇的属性,`drawsAsynchronously`属性对传入`-drawLayer:inContext:`的CGContext进行改动,允许CGContext延缓绘制命令的执行以至于不阻塞用户交互。
diff --git "a/14-\345\233\276\345\203\217IO/\345\233\276\345\203\217IO.md" "b/14-\345\233\276\345\203\217IO/\345\233\276\345\203\217IO.md"
index ca0048b..d6b76e0 100644
--- "a/14-\345\233\276\345\203\217IO/\345\233\276\345\203\217IO.md"
+++ "b/14-\345\233\276\345\203\217IO/\345\233\276\345\203\217IO.md"
@@ -1,10 +1,10 @@
-#图像IO
+# 图像IO
*潜伏期值得思考* - 凯文 帕萨特
在第13章“高效绘图”中,我们研究了和Core Graphics绘图相关的性能问题,以及如何修复。和绘图性能相关紧密相关的是图像性能。在这一章中,我们将研究如何优化从闪存驱动器或者网络中加载和显示图片。
-##加载和潜伏
+## 加载和潜伏
绘图实际消耗的时间通常并不是影响性能的因素。图片消耗很大一部分内存,而且不太可能把需要显示的图片都保留在内存中,所以需要在应用运行的时候周期性地加载和卸载图片。
@@ -16,7 +16,7 @@
有时候图片也需要从远程网络连接中下载,这将会比从磁盘加载要消耗更多的时间,甚至可能由于连接问题而加载失败(在几秒钟尝试之后)。你不能在主线程中加载网络,并在屏幕冻结期间期望用户去等待它,所以需要后台线程。
-###线程加载
+### 线程加载
在第12章“性能调优”我们的联系人列表例子中,图片都非常小,所以可以在主线程同步加载。但是对于大图来说,这样做就不太合适了,因为加载会消耗很长时间,造成滑动的不流畅。滑动动画会在主线程的run loop中更新,它们是在渲染服务进程中运行的,并因此更容易比CAAnimation遭受CPU相关的性能问题。
@@ -89,7 +89,7 @@
为了在后台线程加载图片,我们可以使用GCD或者`NSOperationQueue`创建自定义线程,或者使用`CATiledLayer`。为了从远程网络加载图片,我们可以使用异步的`NSURLConnection`,但是对本地存储的图片,并不十分有效。
-###GCD和`NSOperationQueue`
+### GCD和`NSOperationQueue`
GCD(Grand Central Dispatch)和`NSOperationQueue`很类似,都给我们提供了队列闭包块来在线程中按一定顺序来执行。`NSOperationQueue`有一个Objecive-C接口(而不是使用GCD的全局C函数),同样在操作优先级和依赖关系上提供了很好的粒度控制,但是需要更多地设置代码。
@@ -141,7 +141,7 @@ GCD(Grand Central Dispatch)和`NSOperationQueue`很类似,都给我们提
图14.3 使用后台线程加载图片来提升性能
-###延迟解压
+### 延迟解压
一旦图片文件被加载就必须要进行解码,解码过程是一个相当复杂的任务,需要消耗非常长的时间。解码后的图片将同样使用相当大的内存。
@@ -215,7 +215,7 @@ CFRelease(source);
}
```
-###`CATiledLayer`
+### `CATiledLayer`
如第6章“专用图层”中的例子所示,`CATiledLayer`可以用来异步加载和显示大型图片,而不阻塞用户输入。但是我们同样可以使用`CATiledLayer`在`UICollectionView`中为每个表格创建分离的`CATiledLayer`实例加载传动器图片,每个表格仅使用一个图层。
@@ -316,7 +316,7 @@ CFRelease(source);
我们可以在加载的同时显示一个占位图片,但这并没有根本解决问题,我们可以做到更好。
-###分辨率交换
+### 分辨率交换
视网膜分辨率(根据苹果营销定义)代表了人的肉眼在正常视角距离能够分辨的最小像素尺寸。但是这只能应用于静态像素。当观察一个移动图片时,你的眼睛就会对细节不敏感,于是一个低分辨率的图片和视网膜质量的图片没什么区别了。
@@ -330,7 +330,7 @@ CFRelease(source);
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
你可以使用这几个方法来检测传送器是否停止滚动,然后加载高分辨率的图片。只要高分辨率图片和低分辨率图片尺寸颜色保持一致,你会很难察觉到替换的过程(确保在同一台机器使用相同的图像程序或者脚本生成这些图片)。
-##缓存
+## 缓存
如果有很多张图片要显示,提前把它们全部都加载进去是不切实际的,但是,这并不意味着,你在遇到加载问题后,当其移出屏幕时就立刻将其销毁。通过选择性的缓存,你就可以避免来回滚动时图片重复性的加载了。
@@ -338,7 +338,7 @@ CFRelease(source);
何时将何物做缓存(做多久)并不总是很明显。幸运的是,大多情况下,iOS都为我们做好了图片的缓存。
-###`+imageNamed:`方法
+### `+imageNamed:`方法
之前我们提到使用`[UIImage imageNamed:]`加载图片有个好处在于可以立刻解压图片而不用等到绘制的时候。但是`[UIImage imageNamed:]`方法有另一个非常显著的好处:它在内存中自动缓存了解压后的图片,即使你自己没有保留对它的任何引用。
@@ -352,7 +352,7 @@ CFRelease(source);
* `[UIImage imageNamed:]`缓存机制并不是公开的,所以你不能很好地控制它。例如,你没法做到检测图片是否在加载之前就做了缓存,不能够设置缓存大小,当图片没用的时候也不能把它从缓存中移除。
-###自定义缓存
+### 自定义缓存
构建一个所谓的缓存系统非常困难。菲尔 卡尔顿曾经说过:“在计算机科学中只有两件难事:缓存和命名”。
@@ -366,7 +366,7 @@ CFRelease(source);
* 缓存回收 - 当内存不够的时候,如何判断哪些缓存需要清空呢?这就需要到你写一个合适的算法了。幸运的是,对缓存回收的问题,苹果提供了一个叫做`NSCache`通用的解决方案
-###NSCache
+### NSCache
`NSCache`和`NSDictionary`类似。你可以通过`-setObject:forKey:`和`-object:forKey:`方法分别来插入,检索。和字典不同的是,`NSCache`在系统低内存的时候自动丢弃存储的对象。
@@ -468,7 +468,7 @@ CFRelease(source);
果然效果更好了!当滚动的时候虽然还有一些图片进入的延迟,但是已经非常罕见了。缓存意味着我们做了更少的加载。这里提前加载逻辑非常粗暴,其实可以把滑动速度和方向也考虑进来,但这已经比之前没做缓存的版本好很多了。
-##文件格式
+## 文件格式
图片加载性能取决于加载大图的时间和解压小图时间的权衡。很多苹果的文档都说PNG是iOS所有图片加载的最好格式。但这是极度误导的过时信息了。
@@ -585,7 +585,7 @@ PNG和JPEG压缩算法作用于两种不同的图片类型:JPEG对于噪点大
但JPEG图片并不是所有情况都适用。如果图片需要一些透明效果,或者压缩之后细节损耗很多,那就该考虑用别的格式了。苹果在iOS系统中对PNG和JPEG都做了一些优化,所以普通情况下都应该用这种格式。也就是说在一些特殊的情况下才应该使用别的格式。
-###混合图片
+### 混合图片
对于包含透明的图片来说,最好是使用压缩透明通道的PNG图片和压缩RGB部分的JPEG图片混合起来加载。这就对任何格式都适用了,而且无论从质量还是文件尺寸还是加载性能来说都和PNG和JPEG的图片相近。相关分别加载颜色和遮罩图片并在运行时合成的代码见14.7。
@@ -627,7 +627,7 @@ PNG和JPEG压缩算法作用于两种不同的图片类型:JPEG对于噪点大
对每张图片都使用两个独立的文件确实有些累赘。JPNG的库([https://github.com/nicklockwood/JPNG](https://github.com/nicklockwood/JPNG))对这个技术提供了一个开源的可以复用的实现,并且添加了直接使用`+imageNamed:`和`+imageWithContentsOfFile:`方法的支持。
-###JPEG 2000
+### JPEG 2000
除了JPEG和PNG之外iOS还支持别的一些格式,例如TIFF和GIF,但是由于他们质量压缩得更厉害,性能比JPEG和PNG糟糕的多,所以大多数情况并不用考虑。
@@ -637,7 +637,7 @@ PNG和JPEG压缩算法作用于两种不同的图片类型:JPEG对于噪点大
但仍然要对JPEG 2000保持关注,因为在后续iOS版本说不定就对它的性能做提升,但是在现阶段,混合图片对更小尺寸和质量的文件性能会更好。
-###PVRTC
+### PVRTC
当前市场的每个iOS设备都使用了Imagination Technologies PowerVR图像芯片作为GPU。PowerVR芯片支持一种叫做PVRTC(PowerVR Texture Compression)的标准图片压缩。
@@ -798,7 +798,7 @@ Xcode包含了一些命令行工具例如*texturetool*来生成PVRTC图片,但
如你所见,非常不容易,如果你对在常规应用中使用PVRTC图片很感兴趣的话(例如基于OpenGL的游戏),可以参考一下`GLView`的库([https://github.com/nicklockwood/GLView](https://github.com/nicklockwood/GLView)),它提供了一个简单的`GLImageView`类,重新实现了`UIImageView`的各种功能,但同时提供了PVRTC图片,而不需要你写任何OpenGL代码。
-##总结
+## 总结
在这章中,我们研究了和图片加载解压相关的性能问题,并延展了一系列解决方案。
diff --git "a/15-\345\233\276\345\261\202\346\200\247\350\203\275/15-\345\233\276\345\261\202\346\200\247\350\203\275.md" "b/15-\345\233\276\345\261\202\346\200\247\350\203\275/15-\345\233\276\345\261\202\346\200\247\350\203\275.md"
index 27562fb..ff1342f 100644
--- "a/15-\345\233\276\345\261\202\346\200\247\350\203\275/15-\345\233\276\345\261\202\346\200\247\350\203\275.md"
+++ "b/15-\345\233\276\345\261\202\346\200\247\350\203\275/15-\345\233\276\345\261\202\346\200\247\350\203\275.md"
@@ -1,23 +1,23 @@
-#图层性能
+# 图层性能
>要更快性能,也要做对正确的事情。
>——Stephen R. Covey
在第14章『图像IO』讨论如何高效地载入和显示图像,通过视图来避免可能引起动画帧率下降的性能问题。在最后一章,我们将着重图层树本身,以发掘最好的性能。
-##隐式绘制
+## 隐式绘制
寄宿图可以通过Core Graphics直接绘制,也可以直接载入一个图片文件并赋值给`contents`属性,或事先绘制一个屏幕之外的`CGContext`上下文。在之前的两章中我们讨论了这些场景下的优化。但是除了常见的显式创建寄宿图,你也可以通过以下三种方式创建隐式的:1,使用特性的图层属性。2,特定的视图。3,特定的图层子类。
了解这个情况为什么发生何时发生是很重要的,它能够让你避免引入不必要的软件绘制行为。
-###文本
+### 文本
`CATextLayer`和`UILabel`都是直接将文本绘制在图层的寄宿图中。事实上这两种方式用了完全不同的渲染方式:在iOS 6及之前,`UILabel`用WebKit的HTML渲染引擎来绘制文本,而`CATextLayer`用的是Core Text.后者渲染更迅速,所以在所有需要绘制大量文本的情形下都优先使用它吧。但是这两种方法都用了软件的方式绘制,因此他们实际上要比硬件加速合成方式要慢。
不论如何,尽可能地避免改变那些包含文本的视图的frame,因为这样做的话文本就需要重绘。例如,如果你想在图层的角落里显示一段静态的文本,但是这个图层经常改动,你就应该把文本放在一个子图层中。
-###光栅化
+### 光栅化
在第四章『视觉效果』中我们提到了`CALayer`的`shouldRasterize`属性,它可以解决重叠透明图层的混合失灵问题。同样在第12章『速度的曲调』中,它也是作为绘制复杂图层树结构的优化方法。
@@ -27,7 +27,7 @@
为了检测你是否正确地使用了光栅化方式,用Instrument查看一下Color Hits Green和Misses Red项目,是否已光栅化图像被频繁地刷新(这样就说明图层并不是光栅化的好选择,或则你无意间触发了不必要的改变导致了重绘行为)。
-##离屏渲染
+## 离屏渲染
Offscreen rendering does not necessarily imply software drawing, but it means that the layer must first be rendered (either by the CPU or GPU) into an offscreen context before being displayed. The layer attributes that trigger offscreen rendering are as follows:
@@ -80,7 +80,7 @@ Offscreen rendering does not necessarily imply software drawing, but it means th
@end
```
-###可伸缩图片
+### 可伸缩图片
另一个创建圆角矩形的方法就是用一个圆形内容图片并结合第二章『寄宿图』提到的`contensCenter`属性去创建一个可伸缩图片(见清单15.2).理论上来说,这个应该比用`CAShapeLayer`要快,因为一个可拉伸图片只需要18个三角形(一个图片是由一个3*3网格渲染而成),然而,许多都需要渲染成一个顺滑的曲线。在实际应用上,二者并没有太大的区别。
@@ -107,13 +107,13 @@ Offscreen rendering does not necessarily imply software drawing, but it means th
使用可伸缩图片的优势在于它可以绘制成任意边框效果而不需要额外的性能消耗。举个例子,可伸缩图片甚至还可以显示出矩形阴影的效果。
-###shadowPath
+### shadowPath
在第2章我们有提到`shadowPath`属性。如果图层是一个简单几何图形如矩形或者圆角矩形(假设不包含任何透明部分或者子图层),创建出一个对应形状的阴影路径就比较容易,而且Core Animation绘制这个阴影也相当简单,避免了屏幕外的图层部分的预排版需求。这对性能来说很有帮助。
如果你的图层是一个更复杂的图形,生成正确的阴影路径可能就比较难了,这样子的话你可以考虑用绘图软件预先生成一个阴影背景图。
-##混合和过度绘制
+## 混合和过度绘制
在第12章有提到,GPU每一帧可以绘制的像素有一个最大限制(就是所谓的fill rate),这个情况下可以轻易地绘制整个屏幕的所有像素。但是如果由于重叠图层的关系需要不停地重绘同一区域的话,掉帧就可能发生了。
@@ -130,13 +130,13 @@ GPU会放弃绘制那些完全被其他图层遮挡的像素,但是要计算
最后,明智地使用`shouldRasterize`属性,可以将一个固定的图层体系折叠成单张图片,这样就不需要每一帧重新合成了,也就不会有因为子图层之间的混合和过度绘制的性能问题了。
-##减少图层数量
+## 减少图层数量
初始化图层,处理图层,打包通过IPC发给渲染引擎,转化成OpenGL几何图形,这些是一个图层的大致资源开销。事实上,一次性能够在屏幕上显示的最大图层数量也是有限的。
确切的限制数量取决于iOS设备,图层类型,图层内容和属性等。但是总得说来可以容纳上百或上千个,下面我们将演示即使图层本身并没有做什么也会遇到的性能问题。
-###裁切
+### 裁切
在对图层做任何优化之前,你需要确定你不是在创建一些不可见的图层,图层在以下几种情况下回事不可见的:
@@ -312,7 +312,7 @@ Core Animation非常擅长处理对视觉效果无意义的图层。但是经常
这个计算机制并不具有普适性,但是原则上是一样。(当你用一个`UITableView`或者`UICollectionView`时,系统做了类似的事情)。这样做的结果?我们的程序可以处理成百上千个『虚拟』图层而且完全没有性能问题!因为它不需要一次性实例化几百个图层。
-###对象回收
+### 对象回收
处理巨大数量的相似视图或图层时还有一个技巧就是回收他们。对象回收在iOS颇为常见;`UITableView`和`UICollectionView`都有用到,`MKMapView`中的动画pin码也有用到,还有其他很多例子。
@@ -423,7 +423,7 @@ Core Animation非常擅长处理对视觉效果无意义的图层。但是经常
你可能注意到当设置图层属性时我们用了一个`CATransaction`来抑制动画效果。在之前并不需要这样做,因为在显示之前我们给所有图层设置一次属性。但是既然图层正在被回收,禁止隐式动画就有必要了,不然当属性值改变时,图层的隐式动画就会被触发。
-###Core Graphics绘制
+### Core Graphics绘制
当排除掉对屏幕显示没有任何贡献的图层或者视图之后,长远看来,你可能仍然需要减少图层的数量。例如,如果你正在使用多个`UILabel`或者`UIImageView`实例去显示固定内容,你可以把他们全部替换成一个单独的视图,然后用`-drawRect:`方法绘制出那些复杂的视图层级。
@@ -431,7 +431,7 @@ Core Animation非常擅长处理对视觉效果无意义的图层。但是经常
你可以自己实验一下这个情况,它包含了性能和栅格化的权衡,但是意味着你可以从图层树上去掉子图层(用`shouldRasterize`,与完全遮挡图层相反)。
-###-renderInContext: 方法
+### -renderInContext: 方法
用Core Graphics去绘制一个静态布局有时候会比用层级的`UIView`实例来得快,但是使用`UIView`实例要简单得多而且比用手写代码写出相同效果要可靠得多,更边说Interface Builder来得直接明了。为了性能而舍弃这些便利实在是不应该。
@@ -441,6 +441,6 @@ Core Animation非常擅长处理对视觉效果无意义的图层。但是经常
当图层内容改变时,刷新这张图片的机会取决于你(不同于`shouldRasterize`,它自动地处理缓存和缓存验证),但是一旦图片被生成,相比于让Core Animation处理一个复杂的图层树,你节省了相当客观的性能。
-##总结
+## 总结
本章学习了使用Core Animation图层可能遇到的性能瓶颈,并讨论了如何避免或减小压力。你学习了如何管理包含上千虚拟图层的场景(事实上只创建了几百个)。同时也学习了一些有用的技巧,选择性地选取光栅化或者绘制图层内容在合适的时候重新分配给CPU和GPU。这些就是我们要讲的关于Core Animation的全部了(至少可以等到苹果发明什么新的玩意儿)。
diff --git "a/2-\345\257\204\345\256\277\345\233\276/\345\257\204\345\256\277\345\233\276.md" "b/2-\345\257\204\345\256\277\345\233\276/\345\257\204\345\256\277\345\233\276.md"
index 46286d6..20205ff 100644
--- "a/2-\345\257\204\345\256\277\345\233\276/\345\257\204\345\256\277\345\233\276.md"
+++ "b/2-\345\257\204\345\256\277\345\233\276/\345\257\204\345\256\277\345\233\276.md"
@@ -1,9 +1,9 @@
-#寄宿图
+# 寄宿图
>图片胜过千言万语,界面抵得上千图片 ——Ben Shneiderman
我们在第一章『图层树』中介绍了CALayer类并创建了一个简单的有蓝色背景的图层。背景颜色还好啦,但是如果它仅仅是展现了一个单调的颜色未免也太无聊了。事实上CALayer类能够包含一张你喜欢的图片,这一章节我们将来探索CALayer的寄宿图(即图层中包含的图)。
-##contents属性
+## contents属性
CALayer 有一个属性叫做`contents`,这个属性的类型被定义为id,意味着它可以是任何类型的对象。在这种情况下,你可以给`contents`属性赋任何值,你的app都能够编译通过。但是,在实践中,如果你给`contents`赋的不是CGImage,那么你得到的图层将是空白的。
`contents`这个奇怪的表现是由Mac OS的历史原因造成的。它之所以被定义为id类型,是因为在Mac OS系统上,这个属性对CGImage和NSImage类型的值都起作用。如果你试图在iOS平台上将UIImage的值赋给它,只能得到一个空白的图层。一些初识Core Animation的iOS开发者可能会对这个感到困惑。
@@ -125,7 +125,7 @@ self.layerView.layer.contentsGravity = kCAGravityResizeAspect;
layer.contentsScale = [UIScreen mainScreen].scale;
```
-##maskToBounds
+## maskToBounds
现在我们的雪人总算是显示了正确的大小,不过你也许已经发现了另外一些事情:它超出了视图的边界。默认情况下,UIView仍然会绘制超过边界的内容或是子视图,在CALayer下也是这样的。
@@ -135,7 +135,7 @@ UIView有一个叫做`clipsToBounds`的属性可以用来决定是否显示超
图2.5 使用`masksToBounds`来修建图层内容
-##contentsRect
+## contentsRect
CALayer的`contentsRect`属性允许我们在图层边框里显示寄宿图的一个子域。这涉及到图片是如何显示和拉伸的,所以要比`contentsGravity`灵活多了
@@ -212,7 +212,7 @@ Mac上有一些商业软件可以为你自动拼合图片,这些工具自动
这些文件通常在OpenGL游戏中使用,不过呢,你要是有兴趣在一些常见的app中使用拼合技术的话,有一个叫做LayerSprites的开源库([https://github.com/nicklockwood/LayerSprites](https://github.com/nicklockwood/LayerSprites)),它能够读取Cocos2D格式中的拼合图并在普通的Core Animation层中显示出来。
-##contentsCenter
+## contentsCenter
本章我们介绍的最后一个和内容有关的属性是`contentsCenter`,看名字你可能会以为它可能跟图片的位置有关,不过这名字着实误导了你。`contentsCenter`其实是一个CGRect,它定义了图层中的可拉伸区域和一个固定的边框。 改变`contentsCenter`的值并不会影响到寄宿图的显示,除非这个图层的大小改变了,你才看得到效果。
@@ -344,7 +344,7 @@ CALayer有一个可选的`delegate`属性,实现了`CALayerDelegate`协议,
当使用寄宿了视图的图层的时候,你也不必实现`-displayLayer:`和`-drawLayer:inContext:`方法来绘制你的寄宿图。通常做法是实现UIView的`-drawRect:`方法,UIView就会帮你做完剩下的工作,包括在需要重绘的时候调用`-display`方法。
-##总结
+## 总结
本章介绍了寄宿图和一些相关的属性。你学到了如何显示和放置图片, 使用拼合技术来显示, 以及用CALayerDelegate和Core Graphics来绘制图层内容。
diff --git "a/3-\345\233\276\345\261\202\345\207\240\344\275\225\345\255\246/\345\233\276\345\261\202\345\207\240\344\275\225\345\255\246.md" "b/3-\345\233\276\345\261\202\345\207\240\344\275\225\345\255\246/\345\233\276\345\261\202\345\207\240\344\275\225\345\255\246.md"
index 9a7f477..9532c9f 100644
--- "a/3-\345\233\276\345\261\202\345\207\240\344\275\225\345\255\246/\345\233\276\345\261\202\345\207\240\344\275\225\345\255\246.md"
+++ "b/3-\345\233\276\345\261\202\345\207\240\344\275\225\345\255\246/\345\233\276\345\261\202\345\207\240\344\275\225\345\255\246.md"
@@ -1,9 +1,9 @@
-#图层几何学
+# 图层几何学
>*不熟悉几何学的人就不要来这里了* --柏拉图学院入口的签名
在第二章里面,我们介绍了图层背后的图片,和一些控制图层坐标和旋转的属性。在这一章中,我们将要看一看图层内部是如何根据父图层和兄弟图层来控制位置和尺寸的。另外我们也会涉及如何管理图层的几何结构,以及它是如何被自动调整和自动布局影响的。
-##布局
+## 布局
`UIView`有三个比较重要的布局属性:`frame`,`bounds`和`center`,`CALayer`对应地叫做`frame`,`bounds`和`position`。为了能清楚区分,图层用了“position”,视图用了“center”,但是他们都代表同样的值。
`frame`代表了图层的外部坐标(也就是在父图层上占据的空间),`bounds`是内部坐标({0, 0}通常是图层的左上角),`center`和`position`都代表了相对于父图层`anchorPoint`所在的位置。`anchorPoint`的属性将会在后续介绍到,现在把它想成图层的中心点就好了。图3.1显示了这些属性是如何相互依赖的。
@@ -23,7 +23,7 @@
图3.2 旋转一个视图或者图层之后的`frame`属性
-##锚点
+## 锚点
之前提到过,视图的`center`属性和图层的`position`属性都指定了`anchorPoint`相对于父图层的位置。图层的`anchorPoint`通过`position`来控制它的`frame`的位置,你可以认为`anchorPoint`是用来移动图层的*把柄*。
默认来说,`anchorPoint`位于图层的中点,所以图层的将会以这个点为中心放置。`anchorPoint`属性并没有被`UIView`接口暴露出来,这也是视图的position属性被叫做“center”的原因。但是图层的`anchorPoint`可以被移动,比如你可以把它置于图层`frame`的左上角,于是图层的内容将会向右下角的`position`方向移动(图3.3),而不是居中了。
@@ -127,7 +127,7 @@
图3.7 钟面,和正确对齐的钟指针
-##坐标系
+## 坐标系
和视图一样,图层在图层树当中也是相对于父图层按层级关系放置,一个图层的`position`依赖于它父图层的`bounds`,如果父图层发生了移动,它的所有子图层也会跟着移动。
这样对于放置图层会更加方便,因为你可以通过移动根图层来将它的子图层作为一个整体来移动,但是有时候你需要知道一个图层的*绝对*位置,或者是相对于另一个图层的位置,而不是它当前父图层的位置。
@@ -141,11 +141,11 @@
这些方法可以把定义在一个图层坐标系下的点或者矩形转换成另一个图层坐标系下的点或者矩形
-###翻转的几何结构
+### 翻转的几何结构
常规说来,在iOS上,一个图层的`position`位于父图层的左上角,但是在Mac OS上,通常是位于左下角。Core Animation可以通过`geometryFlipped`属性来适配这两种情况,它决定了一个图层的坐标是否相对于父图层垂直翻转,是一个`BOOL`类型。在iOS上通过设置它为`YES`意味着它的子图层将会被垂直翻转,也就是将会沿着底部排版而不是通常的顶部(它的所有子图层也同理,除非把它们的`geometryFlipped`属性也设为`YES`)。
-###Z坐标轴
+### Z坐标轴
和`UIView`严格的二维坐标系不同,`CALayer`存在于一个三维空间当中。除了我们已经讨论过的`position`和`anchorPoint`属性之外,`CALayer`还有另外两个属性,`zPosition`和`anchorPointZ`,二者都是在Z轴上描述图层位置的浮点类型。
@@ -287,7 +287,7 @@
这意味着如果改变了图层的z轴顺序,你会发现将不能够检测到最前方的视图点击事件,这是因为被另一个图层遮盖住了,虽然它的`zPosition`值较小,但是在图层树中的顺序靠前。我们将在第五章详细讨论这个问题。
-##自动布局
+## 自动布局
你可能用过`UIViewAutoresizingMask`类型的一些常量,应用于当父视图改变尺寸的时候,相应`UIView`的`frame`也跟着更新的场景(通常用于横竖屏切换)。
@@ -304,7 +304,7 @@
这也是为什么最好使用视图而不是单独的图层来构建应用程序的另一个重要原因之一。
-##总结
+## 总结
本章涉及了`CALayer`的几何结构,包括它的`frame`,`position`和`bounds`,介绍了三维空间内图层的概念,以及如何在独立的图层内响应事件,最后简单说明了在iOS平台中,Core Animation对自动调整和自动布局支持的缺乏。
diff --git "a/4-\350\247\206\350\247\211\346\225\210\346\236\234/4-\350\247\206\350\247\211\346\225\210\346\236\234.md" "b/4-\350\247\206\350\247\211\346\225\210\346\236\234/4-\350\247\206\350\247\211\346\225\210\346\236\234.md"
index 3c1e000..03eec04 100644
--- "a/4-\350\247\206\350\247\211\346\225\210\346\236\234/4-\350\247\206\350\247\211\346\225\210\346\236\234.md"
+++ "b/4-\350\247\206\350\247\211\346\225\210\346\236\234/4-\350\247\206\350\247\211\346\225\210\346\236\234.md"
@@ -1,4 +1,4 @@
-#视觉效果
+# 视觉效果
>嗯,圆和椭圆还不错,但如果是带圆角的矩形呢?
@@ -8,7 +8,7 @@
我们在第三章『图层几何学』中讨论了图层的frame,第二章『寄宿图』则讨论了图层的寄宿图。但是图层不仅仅可以是图片或是颜色的容器;还有一系列内建的特性使得创造美丽优雅的令人深刻的界面元素成为可能。在这一章,我们将会探索一些能够通过使用CALayer属性实现的视觉效果。
-##圆角
+## 圆角
圆角矩形是iOS的一个标志性审美特性。这在iOS的每一个地方都得到了体现,不论是主屏幕图标,还是警告弹框,甚至是文本框。按照这流行程度,你可能会认为一定有不借助Photoshop就能轻易创建圆角矩形的方法。恭喜你,猜对了。
@@ -55,7 +55,7 @@ CALayer有一个叫做`conrnerRadius`的属性控制着图层角的曲率。它
单独控制每个层的圆角曲率是不可能的,所以如果你想创建既有圆角又有直角的图层或视图时,就需要一些不同的方法。比如使用一个图层蒙板(本章稍后会讲到)或者是CAShapeLayer(见第六章『专用图层』)。
-##图层边框
+## 图层边框
CALayer另外两个非常有用属性就是`borderWidth`和`borderColor`。二者共同定义了图层边的绘制样式。这条线(也被称作stroke)沿着图层的`bounds`绘制,同时也包含图层的角。
@@ -99,7 +99,7 @@ CALayer另外两个非常有用属性就是`borderWidth`和`borderColor`。二
图4.4 边框是跟随图层的边界变化的,而不是图层里面的内容
-##阴影
+## 阴影
iOS的另一个常见特性呢,就是阴影。阴影往往可以达到图层深度暗示的效果。也能够用来强调正在显示的图层和优先级(比如说一个在其他视图之前的弹出框),不过有时候他们只是单纯的装饰目的。
@@ -125,7 +125,7 @@ iOS的另一个常见特性呢,就是阴影。阴影往往可以达到图层
图4.6 大一些的阴影位移和角半径会增加图层的深度即视感
-##阴影裁剪
+## 阴影裁剪
和图层边框不同,图层的阴影来源于其内容的确切形状,而不是仅仅是边界和`cornerRadius`。为了计算出阴影的形状,Core Animation会将寄宿图(包括子视图,如果有的话)考虑在内,然后通过这些来完美搭配图层形状从而创建一个阴影(见图4.7)。
@@ -241,7 +241,7 @@ iOS的另一个常见特性呢,就是阴影。阴影往往可以达到图层
如果是一个矩形或者是圆,用`CGPath`会相当简单明了。但是如果是更加复杂一点的图形,`UIBezierPath`类会更合适,它是一个由UIKit提供的在CGPath基础上的Objective-C包装类。
-##图层蒙板
+## 图层蒙板
通过`masksToBounds`属性,我们可以沿边界裁剪图形;通过`cornerRadius`属性,我们还可以设定一个圆角。但是有时候你希望展现的内容不是在一个矩形或圆角矩形。比如,你想展示一个有星形框架的图片,又或者想让一些古卷文字慢慢渐变成背景色,而不是一个突兀的边界。
@@ -417,7 +417,7 @@ view.layer.magnificationFilter = kCAFilterNearest;
图4.19 设置了最近过滤之后的清晰显示
-##组透明
+## 组透明
UIView有一个叫做`alpha`的属性来确定视图的透明度。CALayer有一个等同的属性叫做`opacity`,这两个属性都是影响子层级的。也就是说,如果你给一个图层设置了`opacity`属性,那它的子图层都会受此影响。
@@ -492,7 +492,7 @@ iOS常见的做法是把一个空间的alpha值设置为0.5(50%)以使其看
图4.21 修正后的图
-##总结
+## 总结
这一章介绍了一些可以通过代码应用到图层上的视觉效果,比如圆角,阴影和蒙板。我们也了解了拉伸过滤器和组透明。
diff --git "a/5-\345\217\230\346\215\242/\345\217\230\346\215\242.md" "b/5-\345\217\230\346\215\242/\345\217\230\346\215\242.md"
index 9697987..9fc1b15 100644
--- "a/5-\345\217\230\346\215\242/\345\217\230\346\215\242.md"
+++ "b/5-\345\217\230\346\215\242/\345\217\230\346\215\242.md"
@@ -1,10 +1,10 @@
-#变换
+# 变换
>*很不幸,没人能告诉你母体是什么,你只能自己体会* -- 骇客帝国
在第四章“可视效果”中,我们研究了一些增强图层和它的内容显示效果的一些技术,在这一章中,我们将要研究可以用来对图层旋转,摆放或者扭曲的`CGAffineTransform`,以及可以将扁平物体转换成三维空间对象的`CATransform3D`(而不是仅仅对圆角矩形添加下沉阴影)。
-##仿射变换
+## 仿射变换
在第三章“图层几何学”中,我们使用了`UIView`的`transform`属性旋转了钟的指针,但并没有解释背后运作的原理,实际上`UIView`的`transform`属性是一个`CGAffineTransform`类型,用于在二维空间做旋转,缩放和平移。`CGAffineTransform`是一个可以和二维空间向量(例如`CGPoint`)做乘法的3X2的矩阵(见图5.1)。
@@ -22,7 +22,7 @@
图5.2 仿射和非仿射变换
-###创建一个`CGAffineTransform`
+### 创建一个`CGAffineTransform`
对矩阵数学做一个全面的阐述就超出本书的讨论范围了,不过如果你对矩阵完全不熟悉的话,矩阵变换可能会使你感到畏惧。幸运的是,Core Graphics提供了一系列函数,对完全没有数学基础的开发者也能够简单地做一些变换。如下几个函数都创建了一个`CGAffineTransform`实例:
@@ -71,7 +71,7 @@ C的数学函数库(iOS会自动引入)提供了pi的一些简便的换算
#define DEGREES_TO_RADIANS(x) ((x)/180.0*M_PI)
-###混合变换
+### 混合变换
Core Graphics提供了一系列的函数可以在一个变换的基础上做更深层次的变换,如果做一个既要*缩放*又要*旋转*的变换,这就会非常有用了。例如下面几个函数:
@@ -112,7 +112,7 @@ Core Graphics提供了一系列的函数可以在一个变换的基础上做更
这意味着变换的顺序会影响最终的结果,也就是说旋转之后的平移和平移之后的旋转结果可能不同。
-###剪切变换
+### 剪切变换
Core Graphics为你提供了计算变换矩阵的一些方法,所以很少需要直接设置`CGAffineTransform`的值。除非需要创建一个*斜切*的变换,Core Graphics并没有提供直接的函数。
@@ -145,7 +145,7 @@ CGAffineTransform CGAffineTransformMakeShear(CGFloat x, CGFloat y)
@end
```
-##3D变换
+## 3D变换
CG的前缀告诉我们,`CGAffineTransform`类型属于Core Graphics框架,Core Graphics实际上是一个严格意义上的2D绘图API,并且`CGAffineTransform`仅仅对2D变换有效。
@@ -199,7 +199,7 @@ CG的前缀告诉我们,`CGAffineTransform`类型属于Core Graphics框架,C
其实完全没错,视图看起来更窄实际上是因为我们在用一个斜向的视角看它,而不是*透视*。
-###透视投影
+### 透视投影
在真实世界中,当物体远离我们的时候,由于视角的原因看起来会变小,理论上说远离我们的视图的边要比靠近视角的边跟短,但实际上并没有发生,而我们当前的视角是等距离的,也就是在3D变换中任然保持平行,和之前提到的仿射变换类似。
@@ -242,7 +242,7 @@ CG的前缀告诉我们,`CGAffineTransform`类型属于Core Graphics框架,C
图5.10 应用透视效果之后再次对图层做旋转
-###灭点
+### 灭点
当在透视角度绘图的时候,远离相机视角的物体将会变小变远,当远离到一个极限距离,它们可能就缩成了一个点,于是所有的物体最后都汇聚消失在同一个点。
@@ -256,7 +256,7 @@ Core Animation定义了这个点位于变换图层的`anchorPoint`(通常位
当改变一个图层的`position`,你也改变了它的灭点,做3D变换的时候要时刻记住这一点,当你视图通过调整`m34`来让它更加有3D效果,应该首先把它放置于屏幕中央,然后通过平移来把它移动到指定位置(而不是直接改变它的`position`),这样所有的3D图层都共享一个灭点。
-###`sublayerTransform`属性
+### `sublayerTransform`属性
如果有多个视图或者图层,每个都做3D变换,那就需要分别设置相同的m34值,并且确保在变换之前都在屏幕中央共享同一个`position`,如果用一个函数封装这些操作的确会更加方便,但仍然有限制(例如,你不能在Interface Builder中摆放视图),这里有一个更好的方法。
@@ -303,7 +303,7 @@ Core Animation定义了这个点位于变换图层的`anchorPoint`(通常位
图5.13 通过相同的透视效果分别对视图做变换
-###背面
+### 背面
我们既然可以在3D场景下旋转图层,那么也可以从*背面*去观察它。如果我们在清单5.4中把角度修改为`M_PI`(180度)而不是当前的` M_PI_4`(45度),那么将会把图层完全旋转一个半圈,于是完全背对了相机视角。
@@ -319,7 +319,7 @@ Core Animation定义了这个点位于变换图层的`anchorPoint`(通常位
`CALayer`有一个叫做`doubleSided`的属性来控制图层的背面是否要被绘制。这是一个`BOOL`类型,默认为`YES`,如果设置为`NO`,那么当图层正面从相机视角消失的时候,它将不会被绘制。
-###扁平化图层
+### 扁平化图层
如果对包含已经做过变换的图层的图层做反方向的变换将会发什么什么呢?是不是有点困惑?见图5.15
@@ -404,7 +404,7 @@ Core Animation定义了这个点位于变换图层的`anchorPoint`(通常位
至少当你用正常的`CALayer`的时候是这样,`CALayer`有一个叫做`CATransformLayer`的子类来解决这个问题。具体在第六章“特殊的图层”中将会具体讨论。
-##固体对象
+## 固体对象
现在你懂得了在3D空间的一些图层布局的基础,我们来试着创建一个固态的3D对象(实际上是一个技术上所谓的*空洞*对象,但它以固态呈现)。我们用六个独立的视图来构建一个立方体的各个面。
@@ -607,7 +607,7 @@ Core Animation定义了这个点位于变换图层的`anchorPoint`(通常位
图5.22 动态计算光线效果之后的立方体
-###点击事件
+### 点击事件
你应该能注意到现在可以在第三个表面的顶部看见按钮了,点击它,什么都没发生,为什么呢?
@@ -624,7 +624,7 @@ Core Animation定义了这个点位于变换图层的`anchorPoint`(通常位
图5.23 背景视图不再阻碍按钮,我们可以点击它了
-##总结
+## 总结
这一章涉及了一些2D和3D的变换。你学习了一些矩阵计算的基础,以及如何用Core Animation创建3D场景。你看到了图层背后到底是如何呈现的,并且知道了不能把扁平的图片做成真实的立体效果,最后我们用demo说明了触摸事件的处理,视图中图层添加的层级顺序会比屏幕上显示的顺序更有意义。
diff --git "a/6-\344\270\223\346\234\211\345\233\276\345\261\202/6-\344\270\223\346\234\211\345\233\276\345\261\202.md" "b/6-\344\270\223\346\234\211\345\233\276\345\261\202/6-\344\270\223\346\234\211\345\233\276\345\261\202.md"
index 5045bd9..8f2dcae 100644
--- "a/6-\344\270\223\346\234\211\345\233\276\345\261\202/6-\344\270\223\346\234\211\345\233\276\345\261\202.md"
+++ "b/6-\344\270\223\346\234\211\345\233\276\345\261\202/6-\344\270\223\346\234\211\345\233\276\345\261\202.md"
@@ -1,4 +1,4 @@
-##专用图层
+## 专用图层
>复杂的组织都是专门化的
@@ -17,7 +17,7 @@
* 不会被图层边界剪裁掉。一个`CAShapeLayer`可以在边界之外绘制。你的图层路径不会像在使用Core Graphics的普通`CALayer`一样被剪裁掉(如我们在第二章所见)。
* 不会出现像素化。当你给`CAShapeLayer`做3D变换时,它不像一个有寄宿图的普通图层一样变得像素化。
-###创建一个`CGPath`
+### 创建一个`CGPath`
`CAShapeLayer`可以用来绘制所有能够通过`CGPath`来表示的形状。这个形状不一定要闭合,图层路径也不一定要不可破,事实上你可以在一个图层上绘制好几个不同的形状。你可以控制一些属性比如`lineWith`(线宽,用点表示单位),`lineCap`(线条结尾的样子),和`lineJoin`(线条之间的结合点的样子);但是在图层层面你只有一次机会设置这些属性。如果你想用不同颜色或风格来绘制多个形状,就不得不为每个形状准备一个图层了。
@@ -71,7 +71,7 @@
图6.1 用`CAShapeLayer`绘制一个简单的火柴人
-###圆角
+### 圆角
第二章里面提到了`CAShapeLayer`为创建圆角视图提供了一个方法,就是`CALayer`的`cornerRadius`属性(译者注:其实是在第四章提到的)。虽然使用`CAShapeLayer`类需要更多的工作,但是它有一个优势就是可以单独指定每个角。
@@ -88,7 +88,7 @@ UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorn
我们可以通过这个图层路径绘制一个既有直角又有圆角的视图。如果我们想依照此图形来剪裁视图内容,我们可以把`CAShapeLayer`作为视图的宿主图层,而不是添加一个子视图(图层蒙板的详细解释见第四章『视觉效果』)。
-##CATextLayer
+## CATextLayer
用户界面是无法从一个单独的图片里面构建的。一个设计良好的图标能够很好地表现一个按钮或控件的意图,不过你迟早都要需要一个不错的老式风格的文本标签。
@@ -163,7 +163,7 @@ textLayer.contentsScale = [UIScreen mainScreen].scale;
另外,`CATextLayer`的`string`属性并不是你想象的`NSString`类型,而是`id`类型。这样你既可以用`NSString`也可以用`NSAttributedString`来指定文本了(注意,`NSAttributedString`并不是`NSString`的子类)。属性化字符串是iOS用来渲染字体风格的机制,它以特定的方式来决定指定范围内的字符串的原始信息,比如字体,颜色,字重,斜体等。
-###富文本
+### 富文本
iOS 6中,Apple给`UILabel`和其他UIKit文本视图添加了直接的属性化字符串的支持,应该说这是一个很方便的特性。不过事实上从iOS3.2开始`CATextLayer`就已经支持属性化字符串了。这样的话,如果你想要支持更低版本的iOS系统,`CATextLayer`无疑是你向界面中增加富文本的好办法,而且也不用去跟复杂的Core Text打交道,也省了用`UIWebView`的麻烦。
@@ -457,7 +457,7 @@ iOS 6中,Apple给`UILabel`和其他UIKit文本视图添加了直接的属性
图6.5 同一视角下的俩不同变换的立方体
-##CAGradientLayer
+## CAGradientLayer
`CAGradientLayer`是用来生成两种或更多颜色平滑渐变的。用Core Graphics复制一个`CAGradientLayer`并将内容绘制到一个普通图层的寄宿图也是有可能的,但是`CAGradientLayer`的真正好处在于绘制使用了硬件加速。
@@ -500,7 +500,7 @@ iOS 6中,Apple给`UILabel`和其他UIKit文本视图添加了直接的属性
图6.6 用`CAGradientLayer`实现简单的两种颜色的对角线渐变
-###多重渐变
+### 多重渐变
如果你愿意,`colors`属性可以包含很多颜色,所以创建一个彩虹一样的多重渐变也是很简单的。默认情况下,这些颜色在空间上均匀地被渲染,但是我们可以用`locations`属性来调整空间。`locations`属性是一个浮点数值的数组(以`NSNumber`包装)。这些浮点数定义了`colors`属性中每个不同颜色的位置,同样的,也是以单位坐标系进行标定。0.0代表着渐变的开始,1.0代表着结束。
@@ -536,11 +536,11 @@ iOS 6中,Apple给`UILabel`和其他UIKit文本视图添加了直接的属性
图6.7 用`locations`构造偏移至左上角的三色渐变
-##CAReplicatorLayer
+## CAReplicatorLayer
`CAReplicatorLayer`的目的是为了高效生成许多相似的图层。它会绘制一个或多个图层的子图层,并在每个复制体上应用不同的变换。看上去演示能够更加解释这些,我们来写个例子吧。
-###重复图层(Repeating Layers)
+### 重复图层(Repeating Layers)
清单6.8中,我们在屏幕的中间创建了一个小白色方块图层,然后用`CAReplicatorLayer`生成十个图层组成一个圆圈。`instanceCount`属性指定了图层需要重复多少次。`instanceTransform`指定了一个`CATransform3D`3D变换(这种情况下,下一图层的位移和旋转将会移动到圆圈的下一个点)。
@@ -593,7 +593,7 @@ iOS 6中,Apple给`UILabel`和其他UIKit文本视图添加了直接的属性
注意到当图层在重复的时候,他们的颜色也在变化:这是用`instanceBlueOffset`和`instanceGreenOffset`属性实现的。通过逐步减少蓝色和绿色通道,我们逐渐将图层颜色转换成了红色。这个复制效果看起来很酷,但是`CAReplicatorLayer`真正应用到实际程序上的场景比如:一个游戏中导弹的轨迹云,或者粒子爆炸(尽管iOS 5已经引入了`CAEmitterLayer`,它更适合创建任意的粒子效果)。除此之外,还有一个实际应用是:反射。
-###反射
+### 反射
使用`CAReplicatorLayer`并应用一个负比例变换于一个复制图层,你就可以创建指定视图(或整个视图层次)内容的镜像图片,这样就创建了一个实时的『反射』效果。让我们来尝试实现这个创意:指定一个继承于`UIView`的`ReflectionView`,它会自动产生内容的反射效果。实现这个效果的代码很简单(见清单6.9),实际上用`ReflectionView`实现这个效果会更简单,我们只需要把`ReflectionView`的实例放置于Interface Builder(见图6.9),它就会实时生成子视图的反射,而不需要别的代码(见图6.10).
@@ -654,7 +654,7 @@ iOS 6中,Apple给`UILabel`和其他UIKit文本视图添加了直接的属性
开源代码`ReflectionView`完成了一个自适应的渐变淡出效果(用`CAGradientLayer`和图层蒙板实现),代码见 https://github.com/nicklockwood/ReflectionView
-##CAScrollLayer
+## CAScrollLayer
对于一个未转换的图层,它的`bounds`和它的`frame`是一样的,`frame`属性是由`bounds`属性自动计算而出的,所以更改任意一个值都会更新其他值。
@@ -734,7 +734,7 @@ iOS 6中,Apple给`UILabel`和其他UIKit文本视图添加了直接的属性
看到这些方法和属性名,你也许会以为这些方法给每个`CALayer`实例增加了滑动功能。但是事实上他们只是放置在`CAScrollLayer`中的图层的实用方法。`scrollPoint:`方法从图层树中查找并找到第一个可用的`CAScrollLayer`,然后滑动它使得指定点成为可视的。`scrollRectToVisible:`方法实现了同样的事情只不过是作用在一个矩形上的。`visibleRect`属性决定图层(如果存在的话)的哪部分是当前的可视区域。如果你自己实现这些方法就会相对容易明白一点,但是`CAScrollLayer`帮你省了这些麻烦,所以当涉及到实现图层滑动的时候就可以用上了。
-##CATiledLayer
+## CATiledLayer
有些时候你可能需要绘制一个很大的图片,常见的例子就是一个高像素的照片或者是地球表面的详细地图。iOS应用通畅运行在内存受限的设备上,所以读取整个图片到内存中是不明智的。载入大图可能会相当地慢,那些对你看上去比较方便的做法(在主线程调用`UIImage`的`-imageNamed:`方法或者`-imageWithContentsOfFile:`方法)将会阻塞你的用户界面,至少会引起动画卡顿现象。
@@ -742,7 +742,7 @@ iOS 6中,Apple给`UILabel`和其他UIKit文本视图添加了直接的属性
`CATiledLayer`为载入大图造成的性能问题提供了一个解决方案:将大图分解成小片然后将他们单独按需载入。让我们用实验来证明一下。
-###小片裁剪
+### 小片裁剪
这个示例中,我们将会从一个2048*2048分辨率的雪人图片入手。为了能够从`CATiledLayer`中获益,我们需要把这个图片裁切成许多小一些的图片。你可以通过代码来完成这件事情,但是如果你在运行时读入整个图片并裁切,那`CATiledLayer`这些所有的性能优点就损失殆尽了。理想情况下来说,最好能够逐个步骤来实现。
@@ -884,7 +884,7 @@ Snowman_07_07.jpg
当你滑动这个图片,你会发现当`CATiledLayer`载入小图的时候,他们会淡入到界面中。这是`CATiledLayer`的默认行为。(你可能已经在iOS 6之前的苹果地图程序中见过这个效果)你可以用`fadeDuration`属性改变淡入时长或直接禁用掉。`CATiledLayer`(不同于大部分的`UIKit`和Core Animation方法)支持多线程绘制,`-drawLayer:inContext:`方法可以在多个线程中同时地并发调用,所以请小心谨慎地确保你在这个方法中实现的绘制代码是线程安全的。
-###Retina小图
+### Retina小图
你也许已经注意到了这些小图并不是以Retina的分辨率显示的。为了以屏幕的原生分辨率来渲染`CATiledLayer`,我们需要设置图层的`contentsScale`来匹配`UIScreen`的`scale`属性:
@@ -904,7 +904,7 @@ NSInteger y = floor(bounds.origin.y / layer.tileSize.height * scale);
通过这个方法纠正`scale`也意味着我们的雪人图将以一半的大小渲染在Retina设备上(总尺寸是1024\*1024,而不是2048\*2048)。这个通常都不会影响到用`CATiledLayer`正常显示的图片类型(比如照片和地图,他们在设计上就是要支持放大缩小,能够在不同的缩放条件下显示),但是也需要在心里明白。
-##CAEmitterLayer
+## CAEmitterLayer
在iOS 5中,苹果引入了一个新的`CALayer`子类叫做`CAEmitterLayer`。`CAEmitterLayer`是一个高性能的粒子引擎,被用来创建实时例子动画如:烟雾,火,雨等等这些效果。
@@ -974,7 +974,7 @@ NSInteger y = floor(bounds.origin.y / layer.tileSize.height * scale);
图6.14 禁止混色之后的火焰粒子
-##CAEAGLLayer
+## CAEAGLLayer
当iOS要处理高性能图形绘制,必要时就是OpenGL。应该说它应该是最后的杀手锏,至少对于非游戏的应用来说是的。因为相比Core Animation和UIkit框架,它不可思议地复杂。
@@ -1125,7 +1125,7 @@ OpenGL提供了Core Animation的基础,它是底层的C接口,直接和iPhon
在一个真正的OpenGL应用中,我们可能会用`NSTimer`或`CADisplayLink`周期性地每秒钟调用`-drawRrame`方法60次,同时会将几何图形生成和绘制分开以便不会每次都重新生成三角形的顶点(这样也可以让我们绘制其他的一些东西而不是一个三角形而已),不过上面这个例子已经足够演示了绘图原则了。
-##AVPlayerLayer
+## AVPlayerLayer
最后一个图层类型是`AVPlayerLayer`。尽管它不是Core Animation框架的一部分(AV前缀看上去像),`AVPlayerLayer`是有别的框架(AVFoundation)提供的,它和Core Animation紧密地结合在一起,提供了一个`CALayer`子类来显示自定义的内容类型。
@@ -1205,7 +1205,7 @@ OpenGL提供了Core Animation的基础,它是底层的C接口,直接和iPhon
图6.17 3D视角下的边框和圆角`AVPlayerLayer`
-##总结
+## 总结
这一章我们简要概述了一些专用图层以及用他们实现的一些效果,我们只是了解到这些图层的皮毛,像`CATiledLayer`和`CAEMitterLayer`这些类可以单独写一章的。但是,重点是记住`CALayer`是用处很大的,而且它并没有为所有可能的场景进行优化。为了获得Core Animation最好的性能,你需要为你的工作选对正确的工具,希望你能够挖掘这些不同的`CALayer`子类的功能。
这一章我们通过`CAEmitterLayer`和`AVPlayerLayer`类简单地接触到了一些动画,在第二章,我们将继续深入研究动画,就从隐式动画开始。
diff --git "a/7-\351\232\220\345\274\217\345\212\250\347\224\273/\351\232\220\345\274\217\345\212\250\347\224\273.md" "b/7-\351\232\220\345\274\217\345\212\250\347\224\273/\351\232\220\345\274\217\345\212\250\347\224\273.md"
index f1a141e..8c58af3 100644
--- "a/7-\351\232\220\345\274\217\345\212\250\347\224\273/\351\232\220\345\274\217\345\212\250\347\224\273.md"
+++ "b/7-\351\232\220\345\274\217\345\212\250\347\224\273/\351\232\220\345\274\217\345\212\250\347\224\273.md"
@@ -1,10 +1,10 @@
-#隐式动画
+# 隐式动画
>*按照我的意思去做,而不是我说的。* -- 埃德娜,辛普森
我们在第一部分讨论了除了动画之外,Core Animation可以做到的任何事情。但是动画是Core Animation库一个非常显著的特性。这一章我们来看看它是怎么工作的。具体来说,我们先来讨论框架自动实现的*隐式动画*(除非你明确禁用了这个功能)。
-##事务
+## 事务
Core Animation基于一个假设,说屏幕上的任何东西都可以(或者可能)做动画。你并不需要在Core Animation中手动打开动画,但是你需要明确地关闭它,否则它会一直存在。
@@ -92,7 +92,7 @@ Core Animation在每个*run loop*周期中自动开始一次新的事务(run l
`CATransaction`的`+begin`和`+commit`方法在`+animateWithDuration:animations:`内部自动调用,这样block中所有属性的改变都会被事务所包含。这样也可以避免开发者由于对`+begin`和`+commit`匹配的失误造成的风险。
-##完成块
+## 完成块
基于`UIView`的block的动画允许你在动画结束的时候提供一个完成的动作。`CATranscation`接口提供的`+setCompletionBlock:`方法也有同样的功能。我们来调整上个例子,在颜色变化结束之后执行一些操作。我们来添加一个完成之后的block,用来在每次颜色变化结束之后切换到另一个旋转90的动画。代码见清单7.3,运行结果见图7.2。
@@ -128,7 +128,7 @@ Core Animation在每个*run loop*周期中自动开始一次新的事务(run l
注意旋转动画要比颜色渐变快得多,这是因为完成块是在颜色渐变的事务提交并出栈之后才被执行,于是,用默认的事务做变换,默认的时间也就变成了0.25秒。
-##图层行为
+## 图层行为
现在来做个实验,试着直接对UIView关联的图层做动画而不是一个单独的图层。清单7.4是对清单7.2代码的一点修改,移除了`colorLayer`,并且直接设置`layerView`关联图层的背景色。
@@ -277,7 +277,7 @@ Core Animation在每个*run loop*周期中自动开始一次新的事务(run l
图7.3 使用推进过渡的色值动画
-##呈现与模型
+## 呈现与模型
`CALayer`的属性行为其实很不正常,因为改变一个图层的属性并没有立刻生效,而是通过一段时间渐变更新。这是怎么做到的呢?
@@ -352,7 +352,7 @@ Core Animation在每个*run loop*周期中自动开始一次新的事务(run l
```
@end
-##总结
+## 总结
这一章讨论了隐式动画,还有Core Animation对指定属性选择合适的动画行为的机制。同时你知道了UIKit是如何充分利用Core Animation的隐式动画机制来强化它的显式系统,以及动画是如何被默认禁用并且当需要的时候启用的。最后,你了解了呈现和模型图层,以及Core Animation是如何通过它们来判断出图层当前位置以及将要到达的位置。
diff --git "a/8-\346\230\276\345\274\217\345\212\250\347\224\273/\346\230\276\345\274\217\345\212\250\347\224\273.md" "b/8-\346\230\276\345\274\217\345\212\250\347\224\273/\346\230\276\345\274\217\345\212\250\347\224\273.md"
index d1b1fbc..d10b7ef 100644
--- "a/8-\346\230\276\345\274\217\345\212\250\347\224\273/\346\230\276\345\274\217\345\212\250\347\224\273.md"
+++ "b/8-\346\230\276\345\274\217\345\212\250\347\224\273/\346\230\276\345\274\217\345\212\250\347\224\273.md"
@@ -1,14 +1,14 @@
-#显式动画
+# 显式动画
> 如果想让事情变得顺利,只有靠自己 -- 夏尔·纪尧姆
上一章介绍了隐式动画的概念。隐式动画是iOS平台上创建动态用户界面的一种简单方式,也是UIKit动画机制的基础,不过它并不能涵盖所有的动画类型。在这一章中,我们将要研究一下*显式动画*,它能够对一些属性做指定的自定义动画,或者创建非线性动画,比如沿着任意一条曲线移动。
-##属性动画
+## 属性动画
首先我们来探讨一下*属性动画*。属性动画作用于图层的某个单一属性,并指定了它的一个目标值,或者一连串将要做动画的值。属性动画分为两种:*基础*和*关键帧*。
-###基础动画
+### 基础动画
动画其实就是一段时间内发生的改变,最简单的形式就是从一个值改变到另一个值,这也是`CABasicAnimation`最主要的功能。`CABasicAnimation`是`CAPropertyAnimation`的一个子类,而`CAPropertyAnimation`的父类是`CAAnimation`,`CAAnimation`同时也是Core Animation所有动画类型的抽象基类。作为一个抽象类,`CAAnimation`本身并没有做多少工作,它提供了一个计时函数(见第十章“缓冲”),一个委托(用于反馈动画状态)以及一个`removedOnCompletion`,用于标识动画是否该在结束后自动释放(默认`YES`,为了防止内存泄露)。`CAAnimation`同时实现了一些协议,包括`CAAction`(允许`CAAnimation`的子类可以提供图层行为),以及`CAMediaTiming`(第九章“图层时间”将会详细解释)。
@@ -151,7 +151,7 @@ self.colorLayer.backgroundColor = color.CGColor;
解决看起来如此简单的一个问题都着实麻烦,但是别的方案会更加复杂。如果不在动画开始之前去更新目标属性,那么就只能在动画完全结束或者取消的时候更新它。这意味着我们需要精准地在动画结束之后,图层返回到原始值之前更新属性。那么该如何找到这个点呢?
-###CAAnimationDelegate
+### CAAnimationDelegate
在第七章使用隐式动画的时候,我们可以在`CATransaction`完成块中检测到动画的完成。但是这种方式并不适用于显式动画,因为这里的动画和事务并没太多关联。
@@ -304,7 +304,7 @@ self.colorLayer.backgroundColor = color.CGColor;
我们可以用一个`fillMode`属性来解决这个问题,下一章会详细说明,这里知道在动画之前设置它比在动画结束之后更新属性更加方便。
-###关键帧动画
+### 关键帧动画
`CABasicAnimation`揭示了大多数隐式动画背后依赖的机制,这的确很有趣,但是显式地给图层添加`CABasicAnimation`相较于隐式动画而言,只能说费力不讨好。
@@ -419,7 +419,7 @@ self.colorLayer.backgroundColor = color.CGColor;
图8.2 匹配曲线切线方向的飞船图层
-###虚拟属性
+### 虚拟属性
之前提到过属性动画实际上是针对于关键*路径*而不是一个键,这就意味着可以对子属性甚至是*虚拟属性*做动画。但是*虚拟*属性到底是什么呢?
@@ -510,7 +510,7 @@ self.colorLayer.backgroundColor = color.CGColor;
`CAValueFunction`看起来似乎是对那些不能简单相加的属性(例如变换矩阵)做动画的非常有用的机制,但由于`CAValueFunction`的实现细节是私有的,所以目前不能通过继承它来自定义。你可以通过使用苹果目前已近提供的常量(目前都是和变换矩阵的虚拟属性相关,所以没太多使用场景了,因为这些属性都有了默认的实现方式)。
-##动画组
+## 动画组
`CABasicAnimation`和`CAKeyframeAnimation`仅仅作用于单独的属性,而`CAAnimationGroup`可以把这些动画组合在一起。`CAAnimationGroup`是另一个继承于`CAAnimation`的子类,它添加了一个`animations`数组的属性,用来组合别的动画。我们把清单8.6那种关键帧动画和调整图层背景色的基础动画组合起来(清单8.10),结果如图8.3所示。
@@ -559,7 +559,7 @@ self.colorLayer.backgroundColor = color.CGColor;
图8.3 关键帧路径和基础动画的组合
-##过渡
+## 过渡
有时候对于iOS应用程序来说,希望能通过属性动画来对比较难做动画的布局进行一些改变。比如交换一段文本和图片,或者用一段网格视图来替换,等等。属性动画只对图层的可动画属性起作用,所以如果要改变一个不能动画的属性(比如图片),或者从层级关系中添加或者移除图层,属性动画将不起作用。
@@ -635,13 +635,13 @@ self.colorLayer.backgroundColor = color.CGColor;
图8.4 使用`CATransition`对图像平滑淡入淡出
-###隐式过渡
+### 隐式过渡
`CATransision`可以对图层任何变化平滑过渡的事实使得它成为那些不好做动画的属性图层行为的理想候选。苹果当然意识到了这点,并且当设置了`CALayer`的`content`属性的时候,`CATransition`的确是默认的行为。但是对于视图关联的图层,或者是其他隐式动画的行为,这个特性依然是被禁用的,但是对于你自己创建的图层,这意味着对图层`contents`图片做的改动都会自动附上淡入淡出的动画。
我们在第七章使用`CATransition`作为一个图层行为来改变图层的背景色,当然`backgroundColor`属性可以通过正常的`CAPropertyAnimation`来实现,但这不是说不可以用`CATransition`来实行。
-###对图层树的动画
+### 对图层树的动画
`CATransition`并不作用于指定的图层属性,这就是说你可以在即使不能准确得知改变了什么的情况下对图层做动画,例如,在不知道`UITableView`哪一行被添加或者删除的情况下,直接就可以平滑地刷新它,或者在不知道`UIViewController`内部的视图层级的情况下对两个不同的实例做过渡动画。
@@ -682,7 +682,7 @@ self.colorLayer.backgroundColor = color.CGColor;
@end
```
-###自定义动画
+### 自定义动画
我们证实了过渡是一种对那些不太好做平滑动画属性的强大工具,但是`CATransition`的提供的动画类型太少了。
@@ -783,7 +783,7 @@ self.colorLayer.backgroundColor = color.CGColor;
这里有个警告:`-renderInContext:`捕获了图层的图片和子图层,但是不能对子图层正确地处理变换效果,而且对视频和OpenGL内容也不起作用。但是用`CATransition`,或者用私有的截屏方式就没有这个限制了。
-##在动画过程中取消动画
+## 在动画过程中取消动画
之前提到过,你可以用`-addAnimation:forKey:`方法中的`key`参数来在添加动画之后检索一个动画,使用如下方法:
@@ -857,7 +857,7 @@ self.colorLayer.backgroundColor = color.CGColor;
图8.6 通过开始和停止按钮控制的旋转动画
-##总结
+## 总结
这一章中,我们涉及了属性动画(你可以对单独的图层属性动画有更加具体的控制),动画组(把多个属性动画组合成一个独立单元)以及过度(影响整个图层,可以用来对图层的任何内容做任何类型的动画,包括子图层的添加和移除)。
diff --git "a/9-\345\233\276\345\261\202\346\227\266\351\227\264/\345\233\276\345\261\202\346\227\266\351\227\264.md" "b/9-\345\233\276\345\261\202\346\227\266\351\227\264/\345\233\276\345\261\202\346\227\266\351\227\264.md"
index 45470fb..bc0298c 100644
--- "a/9-\345\233\276\345\261\202\346\227\266\351\227\264/\345\233\276\345\261\202\346\227\266\351\227\264.md"
+++ "b/9-\345\233\276\345\261\202\346\227\266\351\227\264/\345\233\276\345\261\202\346\227\266\351\227\264.md"
@@ -1,14 +1,14 @@
-#图层时间
+# 图层时间
>*时间和空间最大的区别在于,时间不能被复用* -- 弗斯特梅里克
在上面两章中,我们探讨了可以用`CAAnimation`和它的子类实现的多种图层动画。动画的发生是需要持续一段时间的,所以*计时*对整个概念来说至关重要。在这一章中,我们来看看`CAMediaTiming`,看看Core Animation是如何跟踪时间的。
-##`CAMediaTiming`协议
+## `CAMediaTiming`协议
`CAMediaTiming`协议定义了在一段动画内用来控制逝去时间的属性的集合,`CALayer`和`CAAnimation`都实现了这个协议,所以时间可以被任意基于一个图层或者一段动画的类控制。
-###持续和重复
+### 持续和重复
我们在第八章“显式动画”中简单提到过`duration`(`CAMediaTiming`的属性之一),`duration`是一个`CFTimeInterval`的类型(类似于`NSTimeInterval`的一种双精度浮点类型),对将要进行的动画的一次迭代指定了时间。
@@ -131,7 +131,7 @@
@end
```
-###相对时间
+### 相对时间
每次讨论到Core Animation,时间都是相对的,每个动画都有它自己描述的时间,可以独立地加速,延时或者偏移。
@@ -215,7 +215,7 @@
图9.3 测试时间偏移和速度的简单的应用程序
-###`fillMode`
+### `fillMode`
对于`beginTime`非0的一段动画来说,会出现一个当动画添加到图层上但什么也没发生的状态。类似的,`removeOnCompletion`被设置为`NO`的动画将会在动画结束的时候仍然保持之前的状态。这就产生了一个问题,当动画开始之前和动画结束之后,被设置动画的属性将会是什么值呢?
@@ -234,13 +234,13 @@
这就对避免在动画结束的时候急速返回提供另一种方案(见第八章)。但是记住了,当用它来解决这个问题的时候,需要把`removeOnCompletion`设置为`NO`,另外需要给动画添加一个非空的键,于是可以在不需要动画的时候把它从图层上移除。
-##层级关系时间
+## 层级关系时间
在第三章“图层几何学”中,你已经了解到每个图层是如何相对在图层树中的父图层定义它的坐标系的。动画时间和它类似,每个动画和图层在时间上都有它自己的层级概念,相对于它的父亲来测量。对图层调整时间将会影响到它本身和子图层的动画,但不会影响到父图层。另一个相似点是所有的动画都被按照层级组合(使用`CAAnimationGroup`实例)。
对`CALayer`或者`CAAnimationGroup`调整`duration`和`repeatCount`/`repeatDuration`属性并不会影响到子动画。但是`beginTime`,`timeOffset`和`speed`属性将会影响到子动画。然而在层级关系中,`beginTime`指定了父图层开始动画(或者组合关系中的父动画)和对象将要开始自己动画之间的偏移。类似的,调整`CALayer`和`CAGroupAnimation`的`speed`属性将会对动画以及子动画速度应用一个缩放的因子。
-###全局时间和本地时间
+### 全局时间和本地时间
CoreAnimation有一个*全局时间*的概念,也就是所谓的*马赫时间*(“马赫”实际上是iOS和Mac OS系统内核的命名)。马赫时间在设备上所有进程都是全局的--但是在不同设备上并不是全局的--不过这已经足够对动画的参考点提供便利了,你可以使用`CACurrentMediaTime`函数来访问马赫时间:
@@ -261,7 +261,7 @@ CoreAnimation有一个*全局时间*的概念,也就是所谓的*马赫时间*
当用来同步不同图层之间有不同的`speed`,`timeOffset`和`beginTime`的动画,这些方法会很有用。
-###暂停,倒回和快进
+### 暂停,倒回和快进
设置动画的`speed`属性为0可以暂停动画,但在动画被添加到图层之后不太可能再修改它了,所以不能对正在进行的动画使用这个属性。给图层添加一个`CAAnimation`实际上是给动画对象做了一个不可改变的拷贝,所以对原始动画对象属性的改变对真实的动画并没有作用。相反,直接用`-animationForKey:`来检索图层正在进行的动画可以返回正确的动画对象,但是修改它的属性将会抛出异常。
@@ -276,7 +276,7 @@ CoreAnimation有一个*全局时间*的概念,也就是所谓的*马赫时间*
你也可以通过这种方式来*减速*,但其实也可以在模拟器通过切换慢速动画来实现。
-##手动动画
+## 手动动画
`timeOffset`一个很有用的功能在于它可以让你手动控制动画进程,通过设置`speed`为0,可以禁用动画的自动播放,然后来使用`timeOffset`来来回显示动画序列。这可以使得运用手势来手动控制动画变得很简单。
@@ -345,6 +345,6 @@ CoreAnimation有一个*全局时间*的概念,也就是所谓的*马赫时间*
在这个例子中的确是这样,但是对于比如说关键帧这样更加复杂的情况,或者有多个图层的动画组,相对于实时计算每个图层的属性而言,这就显得方便的多了。
-##总结
+## 总结
在这一章,我们了解了`CAMediaTiming`协议,以及Core Animation用来操作时间控制动画的机制。在下一章,我们将要接触`缓冲`,另一个用来使动画更加真实的操作时间的技术。