Skip to content

Commit

Permalink
Merge pull request #87 from 963239327/patch-7
Browse files Browse the repository at this point in the history
Update 6-专有图层.md
  • Loading branch information
qunten authored Jun 5, 2018
2 parents d92a8c1 + a3f3d33 commit a331b2a
Showing 1 changed file with 10 additions and 10 deletions.
20 changes: 10 additions & 10 deletions 6-专有图层/6-专有图层.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@

在第四章『视觉效果』我们学习到了不使用图片的情况下用`CGPath`去构造任意形状的阴影。如果我们能用同样的方式创建相同形状的图层就好了。

`CAShapeLayer`是一个通过矢量图形而不是bitmap来绘制的图层子类。你指定诸如颜色和线宽等属性,用`CGPath`来定义想要绘制的图形,最后`CAShapeLayer`就自动渲染出来了。当然,你也可以用Core Graphics直接向原始的`CALyer`的内容中绘制一个路径,相比直下,使用`CAShapeLayer`有以下一些优点:
`CAShapeLayer`是一个通过矢量图形而不是bitmap来绘制的图层子类。你指定诸如颜色和线宽等属性,用`CGPath`来定义想要绘制的图形,最后`CAShapeLayer`就自动渲染出来了。当然,你也可以用Core Graphics直接向原始的`CALyer`的内容中绘制一个路径,相比之下,使用`CAShapeLayer`有以下一些优点:

* 渲染快速。`CAShapeLayer`使用了硬件加速,绘制同一图形会比用Core Graphics快很多。
* 高效使用内存。一个`CAShapeLayer`不需要像普通`CALayer`一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。
* 不会被图层边界剪裁掉。一个`CAShapeLayer`可以在边界之外绘制。你的图层路径不会像在使用Core Graphics的普通`CALayer`一样被剪裁掉(如我们在第二章所见)。
* 不会出现像素化。当你给`CAShapeLayer`做3D变换时,它不像一个有寄宿图的普通图层一样变得像素化。
* 不会出现像素化。当你把`CAShapeLayer`放大,或是用3D透视变换将其离相机更近时,它不像一个有寄宿图的普通图层一样变得像素化。

### 创建一个`CGPath`

`CAShapeLayer`可以用来绘制所有能够通过`CGPath`来表示的形状。这个形状不一定要闭合,图层路径也不一定要不可破,事实上你可以在一个图层上绘制好几个不同的形状。你可以控制一些属性比如`lineWith`(线宽,用点表示单位),`lineCap`(线条结尾的样子),和`lineJoin`(线条之间的结合点的样子);但是在图层层面你只有一次机会设置这些属性。如果你想用不同颜色或风格来绘制多个形状,就不得不为每个形状准备一个图层了。
`CAShapeLayer`可以用来绘制所有能够通过`CGPath`来表示的形状。这个形状不一定要闭合,图层路径也不一定要不间断的,事实上你可以在一个图层上绘制好几个不同的形状。你可以控制一些属性比如`lineWith`(线宽,用点表示单位),`lineCap`(线条结尾的样子),和`lineJoin`(线条之间的结合点的样子);但是在图层层面你只有一次机会设置这些属性。如果你想用不同颜色或风格来绘制多个形状,就不得不为每个形状准备一个图层了。

清单6.1 的代码用一个`CAShapeLayer`渲染一个简单的火柴人。`CAShapeLayer`属性是`CGPathRef`类型,但是我们用`UIBezierPath`帮助类创建了图层路径,这样我们就不用考虑人工释放`CGPath`了。图6.1是代码运行的结果。虽然还不是很完美,但是总算知道了大意对吧!
清单6.1 的代码用一个`CAShapeLayer`渲染一个简单的火柴人。`CAShapeLayer``path`属性是`CGPathRef`类型,但是我们用`UIBezierPath`帮助类创建了图层路径,这样我们就不用考虑人工释放`CGPath`了。图6.1是代码运行的结果。虽然还不是很完美,但是总算知道了大意对吧!

清单6.1 用`CAShapeLayer`绘制一个火柴人

Expand Down Expand Up @@ -73,9 +73,9 @@
### 圆角
第二章里面提到了`CAShapeLayer`为创建圆角视图提供了一个方法,就是`CALayer`的`cornerRadius`属性(译者注:其实是在第四章提到的)。虽然使用`CAShapeLayer`类需要更多的工作,但是它有一个优势就是可以单独指定每个角。
第二章里面提到了`CAShapeLayer`是一个代替使用`CALayer`的`cornerRadius`属性来创建视图圆角的替代方法(译者注:其实是在第四章提到的)。虽然使用`CAShapeLayer`类需要更多的工作,但是它有一个优势就是可以单独指定每个角。
我们创建圆角矩形其实就是人工绘制单独的直线和弧度,但是事实上`UIBezierPath`有自动绘制圆角矩形的构造方法,下面这段代码绘制了一个有三个圆角一个直角的矩形:
我们创建圆角矩形其实就是人工绘制单独的直线和弧度,但是事实上`UIBezierPath`有方便地自动绘制圆角矩形的构造方法,下面这段代码绘制了一个有三个圆角一个直角的矩形:
```objective-c
//define path parameters
Expand All @@ -92,7 +92,7 @@ UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorn

用户界面是无法从一个单独的图片里面构建的。一个设计良好的图标能够很好地表现一个按钮或控件的意图,不过你迟早都要需要一个不错的老式风格的文本标签。

如果你想在一个图层里面显示文字,完全可以借助图层代理直接将字符串使用Core Graphics写入图层的内容(这就是UILabel的精髓)。如果越过寄宿于图层的视图,直接在图层上操作,那其实相当繁琐。你要为每一个显示文字的图层创建一个能像图层代理一样工作的类,还要逻辑上判断哪个图层需要显示哪个字符串,更别提还要记录不同的字体,颜色等一系列乱七八糟的东西。
如果你想在一个图层里面显示文字,完全可以借助图层代理直接将字符串使用Core Graphics写入图层的内容(事实上这就是`UILabel`所做的)。如果越过寄宿于图层的视图,直接在图层上操作,那其实相当繁琐。你要为每一个显示文字的图层创建一个能像图层代理一样工作的类,还要逻辑上判断哪个图层需要显示哪个字符串,更别提还要记录不同的字体,颜色等一系列乱七八糟的东西。

万幸的是这些都是不必要的,Core Animation提供了一个`CALayer`的子类`CATextLayer`,它以图层的形式包含了`UILabel`几乎所有的绘制特性,并且额外提供了一些新的特性。

Expand Down Expand Up @@ -244,7 +244,7 @@ iOS 6中,Apple给`UILabel`和其他UIKit文本视图添加了直接的属性
###行距和字距
有必要提一下的是,由于绘制的实现机制不同(Core Text和WebKit),用`CATextLayer`渲染和用`UILabel`渲染出的文本行距和字距也不是不尽相同的
有必要提一下的是,由于绘制的实现机制不同(Core Text和WebKit),用`CATextLayer`渲染和用`UILabel`渲染出的文本行距和字距也是不完全相同的
二者的差异程度(由使用的字体和字符决定)总的来说挺小,但是如果你想正确的显示普通便签和`CATextLayer`就一定要记住这一点。
Expand Down Expand Up @@ -346,11 +346,11 @@ iOS 6中,Apple给`UILabel`和其他UIKit文本视图添加了直接的属性

当我们在构造复杂的3D事物的时候,如果能够组织独立元素就太方便了。比如说,你想创造一个孩子的手臂:你就需要确定哪一部分是孩子的手腕,哪一部分是孩子的前臂,哪一部分是孩子的肘,哪一部分是孩子的上臂,哪一部分是孩子的肩膀等等。

当然是允许独立地移动每个区域的啦。以肘为指点会移动前臂和手,而不是肩膀。Core Animation图层很容易就可以让你在2D环境下做出这样的层级体系下的变换,但是3D情况下就不太可能,因为所有的图层都把他的孩子都平面化到一个场景中(第五章『变换』有提到)。
这样做的原因是允许独立地移动每个区域。以肘为指点会移动前臂和手,而不是肩膀。Core Animation图层很容易就可以让你在2D环境下做出这样的层级体系下的变换,但是3D情况下就不太可能,因为所有的图层都把他的孩子都平面化到一个场景中(第五章『变换』有提到)。

`CATransformLayer`解决了这个问题,`CATransformLayer`不同于普通的`CALayer`,因为它不能显示它自己的内容。只有当存在了一个能作用于子图层的变换它才真正存在。`CATransformLayer`并不平面化它的子图层,所以它能够用于构造一个层级的3D结构,比如我的手臂示例。

用代码创建一个手臂需要相当多的代码,所以我就演示得更简单一些吧:在第五章的立方体示例,我们将通过旋转`camara`来解决图层平面化问题而不是像立方体示例代码中用的`sublayerTransform`。这是一个非常不错的技巧,但是只能作用域单个对象上,如果你的场景包含两个立方体,那我们就不能用这个技巧单独旋转他们了。
用代码创建一个手臂需要相当多的代码,所以我就演示得更简单一些吧:在第五章的立方体示例,我们将通过旋转`camara`来解决图层平面化问题而不是像立方体示例代码中用的`sublayerTransform`。这是一个非常不错的技巧,但是只能作用于单个对象上,如果你的场景包含两个立方体,那我们就不能用这个技巧单独旋转他们了。

那么,就让我们来试一试`CATransformLayer`吧,第一个问题就来了:在第五章,我们是用多个视图来构造了我们的立方体,而不是单独的图层。我们不能在不打乱已有的视图层次的前提下在一个本身不是有寄宿图的图层中放置一个寄宿图图层。我们可以创建一个新的`UIView`子类寄宿在`CATransformLayer`(用`+layerClass`方法)之上。但是,为了简化案例,我们仅仅重建了一个单独的图层,而不是使用视图。这意味着我们不能像第五章一样在立方体表面显示按钮和标签,不过我们现在也用不到这个特性。

Expand Down

0 comments on commit a331b2a

Please sign in to comment.