前言
UIView实际上不是draws它自己在屏幕上,它其实是吧自己画在layer
上面。一个view不会经常redraw,重画。他的drawing是被保存起来的,cached,and the cached version of the drawing (thebitmap backing store) is used where possible.
the view's graphic context is actually the layer's graphics context.
layer extend the power of views.
In particular:// 详细地
Layers have properies that affect drawing
A layer is the recipient and present of a view's drawing. you can modify how a view is drawn on the screen by accessing the layer's properties.使用layer的属性,可以做到view不能做到的事情。Layers can be combined within a single view
view的伙伴layer,可以包含额外的layers.因为layers的目的是去绘画,描绘可见的元素在屏幕上,这样来说,view可以合并多种的不同的碎片(layers的展现),这样来说可以让绘制更加简单,可以让绘制分工合作。layers are the basis of animation
Animation allows you to add clarity, emphasis, and just plain coolness to yourinterface.
Layers are made to be animated;the "CA" in "CALayer" 表示的是"Core Animation"
View and Layer
一个view
的初始化,伴随着CALayer
的初始化。可以通过view.layer
获取。layer
没有相当的view
属性,但是是layer
的代理(delegate
)。
改变潜在的layer
:
import UIKit
class CustomView: UIView {
override class var layerClass:AnyClass {
return CompassLayer.self // CustomView的潜在的layer也就是ComPassLayer,而不是CALayer了
}
}
A layer cannot apeear without a view.
每一个view
都有一个一个潜在的layer
,他们紧密相连的。layer
扮演着view
的drawing
,是因为layer
的drawing
影响着。view
是layer
的代理。view
的属性,通常是access the layer's 属性。
i.e.
设置view.backgroundColor,实际上是设置layer 的backGroundColor,
我们可以直接layer's backgroundColor
而且,view's frame 实际上是layer's frame
注意: 一个CALayer
的代理(delegate
)是可以设置的(to an instance of any class adopting CALayerDelegate),但是UIView
和他的潜在的layer
有一个特殊的联系。view
必须是他的潜在的layer
的delegate
.而且,他一定不能是其他Layer
的代理。如果这样做了,drawing
将会直接停止工作。
The view draws into its layer, and the layer caches that drawing; the layer can then be manipulated, cahnging the view's appearace, without necessarily asking the view to redraw itself.
when the view’s bounds size changes, the drawing system, by default, sim‐ply stretches or repositions the cached layer image, until such time as the view is toldto draw freshly (draw(_:)), replacing the layer’s content.
Layers and Sublayers:图层和子图层
A layer can have sublayer, a layer at most can have one superlayer.
thus, there is a tree of layers.
A view’s subview’s underlying layer is a sublayer of that view’s underlaying layer, justlike any other sublayers of that view’s underlying layer. // 一个view 的 子view 的潜在的layer 是这个view的layer 的潜在的layer的子layer.
layers都有clipsToBounds
的属性,默认是false,所以它可以伸出去。
Like a UIView, a CALayer has an isHidden property that can be set to take it and itssublayers out of the visible interface without actually removing it from its superlayer.
Manipulating the Layer Hierarchy:操作layer的层级
layers 生来有一套read和manupulate layer 的层级。
addSublayer(_:)
insertSublayer(_: at:)
insertSublayer(_:below:), insertSublaer(_:above:)
replaceSublayer(_:with:)
removeFromSuperlayer
不像view的subview属性,a layer's sublayer property is writable; 因此,你能够给一个layer很多sublayers 一次性, 用指定给它的sublayers属性。可以remove 一个Layer的所有sublayers,设置他的sublayers 属性为nil.
尽管一个layer的sublayers有一个顺序(order),
但是这个并不是唯一的显示次序。默认的,它是,但是一个layer
也有一个zPosition
的属性。它也决定了绘制次序。规则是,越低的zPosition
就绘制越早,默认的是0.0
,这个还是很有用处的。
mainView.addSubview(iv)
iv.layer.zPosition = 1
坐标系统也有相应的方法:
convert(_: from:)
convert(_: to:)
Position a Sublayer
layer 的坐标系统与view是相似的,bounds, bounds origin 都在它的左上角。
然而,一个sublayer的position 在他的superlayer中并不是以center来描述的,不像view, 一个layer,没有center的属性。
反而,一个sublayer的postion在他的父layer中是由两个属性定义的:
- position
a point expressed in the superlayer's coordinate system - anchorPoint
where the position point is located, 有关于layer的自己的bounds.it is a CGPoint describing a fraction(or multiple) of the layer's own bounds width and bounds height. (锚点.x/layer's bounds's width,锚点.y/layer's bounds's height).因此,(0.0, 0.0) 就是layer的左上角,(1.0, 1.0)就是layer的右下角
锚点的默认位置是(0.5, 0.5),就会work like the view's center property.
想象sublayer是用别针别在他的superlayer上的,别针别的这个点在sublayer上就是锚点(anchorPoint),在这个superlayer上就是(position)
a view's center 因此是 a layer's position 的一种特定状态。
layer 的 position 和 anchiroint 是相互独立的。改变一个并不会改变另外的一个。
a layer's frame is 纯粹推断出来的属性。当你get frame的时候,it is calculatedfrom the bounds size along with the position and anchorPoint.
When you set the frame, you set the bounds size and position.// 当你设置frame,你就设置了bounds size 和 position
to position a sublayer so that it exactly overlaps its superlayer, you can just set the sublayer’s frame to the superlayer’s bounds
注意:a layer created in code(相对的是view的潜在layer) 有一个frame 和 bounds 是CGRect.zero ,也不会被看见,尽管当你添加他在screen上面
CAScrollLayer
对于一个未转换的图层,它的bounds和它的frame是一样的,frame属性是由bounds属性自动计算而出的,所以更改任意一个值都会更新其他值。
这个链接解释了CAScrollLayer:http://www.jianshu.com/p/6598db897fb9
Layout of Sublayers:Sublayer布局
view的层级实际上是layer的层级.
The positioning of aview within its superview is actually the positioning of its layer within its superlayer(the superview’s layer).
a view can be repositioned and resized automatically in accordance with its autoresizingMask
or through autolayout
based on its constraints.
这里有关于autoresizingMask的链接:http://www.cocoachina.com/ios/20141216/10652.html
因此,Layer是自动布局,如果Layer是view的潜在layer.
Otherwise, there is no automatic layout for layers in iOS. The only option forlayout of layers that are not the underlying layers of views is manual layout that you perform in code.
当一个layer需要布局(layout),不是因为它的bounds
改变了,也不是因为你调用了setNeedsLayout
,you can respond in either of two ways:
- The layer's
layoutSublayers
method is called; to respond, overridelayoutSublayers
in your CALayer subclass - Alternatively(非此即彼),implement
layoutSublayers(of:)
in the layer's delegate.(如果layer是view的潜在layer,view就是layer的delegate)
For your layer to do effective manual layout of its sublayers,you will probably need a way to identify or refer to the sublayers.There is no layer equivalent of viewWithTag(_:)
, so such identification and reference is entirely up to you.A CALayer does have a name property that you might misuse for your own purpose. Key-Value coding in a special way,后面再谈。
view‘s 潜在的layer.layoutSublayers()
或者layoutSublayers(of:)
是在view的·layoutSubviews
之后.Under autolayout, you must call super or else autolayout will break.
而且,这些方法可能会被调用不止一次,在autolayout的过程中;if you’re looking for an automatically generated signal that it’s time to do manual layout of sublayers, a view layout event might be a better choice。
Drawing in a layer
最简单的让什么东西现在在layer中是通过他的content
属性.类比于imageView的image.
It is expexted to be CGImage
(or nil
, 表示没有Image).所以我们也可以这样写:
let lay4 = CALayer()
let im = UIImage(named:"smiley")!
lay4.frame = CGRect(origin:CGPoint(180, 180), size:im.size)
lay4.contents = im.cgImage // 注意cg
mainView.layer.addSublayer(lay4)
如果设置layer的content为image,而不是cgImage,虽然不会爆粗,但是现实不出来的。
有4个方法能够实现给layer的content去draw或者提供,与UIView的 draw(_:)
相似,a layer 是非常保守的,对于调用这些方法(你也不能直接调用他们).
当layer调用这些方法,我们可以这样说,layer在重绘他自己.
- 如果layer的
needsDisplayOnBounds
属性是false(默认就是false),然后唯一的方法让layer去重绘他自己是调用setNeedsDisplay
(或者setNeedsDisplayIn(_:)
)。尽管这样或许不能让layer立即重绘自己;if that;s crucial, then you will also calldisplayIfNeeded
. - 如果
needsDisplayOnBoundsChange
属性是true,然后layer将会也重绘自己,当layer的bounds改变(rather like a view’s .redrawcontent mode)
这里有四个方法能被调用,当一个layer重绘自己的时候;选择一个区实现,(don't try to combine them, you'll just confuse things)
display in subclass
你的CALayer的subclass能够override display. there is no graphics context 此时此刻,所以display
是非常有限的 to setting the contents image.
display(_:) in the delegate
你可以设置CALayer的delegate属性,和实现display(_:)
in the delegate.与CALayer的display一样,there is no graphic context, so you will just be setting the contens image.
draw(in:) in a subclass
你的CALayer的subclass能够override draw(in:)
.the parameter is a graphic context, 在里面你能够直接draw;it is not automatically made the curent context.
draw(_: in:) in the delegate
Assigning a layer a contents image and drawing directly into the layer are, in effect,mutually exclusive. So:
- 假设layer的contents是image.image会马上被显示,this image is shown immediately and replaces whatever drawing may have been displayed in the layer.
- 如果layer 重绘自己,
draw(in:)
或者draw(_: in:)
draws into layer,the drawing 将会替换layer中的contents,无论是Image还是其他的. - 如果layer重绘自己,四个方法中没有任何一个提供任何内容的话,layer将会是empty.
如果是view的潜在layer,你通常不会使用4个方法中的任何一个方法去draw into 你的layer.你会使用view's draw(_:)
.然而,你能够使用这些方法如果你实在想用.如果是这样.你可能想去实现draw(_:)
这个方法无论如何, 不使用那种实现.
原因是这个引起layer
在适当的时候去重绘自己.
当一个view
被sent setNeedsDisplay
-- including when the view first appears -- view的潜在layer
也被sent setNeedsDisplay
, 除非这个view没有实现draw(_:)
(因为再这种情况下,他被假设承view重来不需要redrawing(重绘)).
所以,直接draw一个view的潜在layer,and 如果你想潜在的layer被自动redisplayed, 当view被告知redraw他自己.你应该实现draw(_:) to do nothing.(this technique has no effect on sublayers of the underlying layer)
因此,下面这几个方法是合法的,但是不通常使用的for drawing into a view:
- the view subclass 实现一个空的
draw(_:)
,along with eitherdisplayLayer:
或者draw(_: in:)