第一部分:簡介
一、什麼是CALayer
* 在iOS系統中,你能看得見摸得着的東西基本上都是UIView,比如一個按鈕、一個文本標籤、一個文本輸入框、一個圖標等等,這些都是UIView。
* 其實UIView之所以能顯示在屏幕上,完全是因爲它內部的一個層。
* 在創建UIView對象時,UIView內部會自動創建一個層(即CALayer對象),通過UIView的layer屬性可以訪問這個層。當UIView需要顯示到屏幕上時,會調用 drawRect:方法進行繪圖,並且會將所有內容繪製在自己的層上,繪圖完畢後,系統會將層拷貝到屏幕上,於是就完成了UIView的顯示。
* 換句話說,UIView本身不具備顯示的功能,是它內部的層纔有顯示功能。
二、UIView與CALayer的區別和聯繫
* UIView是iOS系統中界面元素的基礎,所有的界面元素都繼承自它。它本身完全是由CoreAnimation來實現的(Mac下似乎不是這樣)。它真正的繪圖部分,是由一個叫CALayer(Core Animation Layer)的類來管理。UIView本身,更像是一個CALayer的管理器,訪問它的跟繪圖和跟座標有關的屬性,例如frame,bounds等等,實際上內部都是
在訪問它所包含的CALayer的相關屬性。
就是說我們在操作UIView的一些跟繪圖和座標有關的屬性的時候,比如, self.view.backGround =[UIColor yellowColor] ,本質仍然是對CLayer做了操作. 由於代碼封裝我們看不到罷了.
* UIView有個layer屬性,可以返回它的主CALayer實例,UIView有一個layerClass方法,返回主layer所使用的類,UIView的子類,可以通過重載這個方法,來讓UIView使用不同的CALayer來顯示,例如通過
-
- (class) layerClass {
-
return ([CAEAGLLayer class]);
-
}
使某個UIView的子類使用GL來進行繪製。
* UIView的CALayer類似UIView的子View樹形結構,也可以向它的layer上添加子layer,來完成某些特殊的表示。例如下面的代碼
-
grayCover = [[CALayer alloc] init];
-
grayCover.backgroundColor = [[[UIColor blackColor] colorWithAlphaComponent:0.2] CGColor];
-
[self.layer addSubLayer: grayCover];
會在目標View上敷上一層黑色的透明薄膜。
* UIView的layer樹形在系統內部,被系統維護着三份copy(這段理解有點喫不準)。
第一份,邏輯樹,就是代碼裏可以操縱的,例如更改layer的屬性等等就在這一份。
第二份,動畫樹,這是一箇中間層,系統正在這一層上更改屬性,進行各種渲染操作。
第三份,顯示樹,這棵樹的內容是當前正被顯示在屏幕上的內容。
這三棵樹的邏輯結構都是一樣的,區別只有各自的屬性。
*動畫的運作
UIView的主layer以外(我覺得是這樣),對它的subLayer,也就是子layer的屬性進行更改,系統將自動進行動畫生成,動畫持續時間有 個缺省時間,個人感覺大概是0.5秒。在動畫時間裏,系統自動判定哪些屬性更改了,自動對更改的屬性進行動畫插值,生成中間幀然後連續顯示產生動畫效果。
*座標系系統(對position和anchorPoint的關係還是犯暈)
CALayer的座標系系統和UIView有點不一樣,它多了一個叫anchorPoint的屬性,它使用CGPoint結構,但是值域是0~1,也就是 按照比例來設置。這個點是各種圖形變換的座標原點,同時會更改layer的position的位置,它的缺省值是{0.5, 0.5},也就是在layer的中央。
某layer.anchorPoint = CGPointMake(0.f, 0.f);
如果這麼設置,layer的左上角就會被挪到原來的中間的位置,
加上這樣一句就好了
某layer.position = CGPointMake(0.f, 0.f);
*layer可以設置圓角顯示,例如UIButton的效果,也可以設置陰影顯示,但是如果layer樹中的某個layer設置了圓角,樹中所有layer 的陰影效果都將顯示不了了。如果既想有圓角又想要陰影,好像只能做兩個重疊的UIView,一個的layer顯示圓角,一個的layer顯示陰 影.....
上面已經說過了,UIView之所以能夠顯示,完全是因爲內部的CALayer對象。因此,通過操作這個CALayer對象,可以很方便地調整UIView的一些界面屬性,比如:陰影、圓角大小、邊框寬度和顏色等。
三,CALayer的頭文件
-
-
typedef NS_OPTIONS (unsigned int, CAEdgeAntialiasingMask){
-
kCALayerLeftEdge = 1U << 0,
-
kCALayerRightEdge = 1U << 1,
-
kCALayerBottomEdge = 1U << 2,
-
kCALayerTopEdge = 1U << 3,
-
};
-
-
-
+ (instancetype)layer;
-
- (instancetype)init;
-
- (instancetype)initWithLayer:(id)layer;
-
- (nullable id)presentationLayer;
-
- (id)modelLayer;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ (nullable id)defaultValueForKey:(NSString *)key;
-
-
+ (BOOL)needsDisplayForKey:(NSString *)key;
-
-
- (BOOL)shouldArchiveValueForKey:(NSString *)key;
-
-
-
-
@property CGRect bounds;
-
-
-
@property CGPoint position;
-
-
-
@property CGFloat zPosition;
-
-
-
@property CGPoint anchorPoint;
-
-
-
@property CGFloat anchorPointZ;
-
-
-
@property CATransform3D transform;
-
-
-
- (CGAffineTransform)affineTransform;
-
- (void)setAffineTransform:(CGAffineTransform)m;
-
-
-
@property CGRect frame;
-
-
-
@property(getter=isHidden) BOOL hidden;
-
-
-
@property(getter=isDoubleSided) BOOL doubleSided;
-
-
-
-
@property(getter=isGeometryFlipped) BOOL geometryFlipped;
-
-
-
- (BOOL)contentsAreFlipped;
-
-
-
@property(nullable, readonly) CALayer *superlayer;
-
-
-
- (void)removeFromSuperlayer;
-
-
-
@property(nullable, copy) NSArray<CALayer *> *sublayers;
-
-
-
- (void)addSublayer:(CALayer *)layer;
-
-
-
- (void)insertSublayer:(CALayer *)layer atIndex:(unsigned)idx;
-
- (void)insertSublayer:(CALayer *)layer below:(nullable CALayer *)sibling;
-
- (void)insertSublayer:(CALayer *)layer above:(nullable CALayer *)sibling;
-
-
-
- (void)replaceSublayer:(CALayer *)layer with:(CALayer *)layer2;
-
-
-
@property CATransform3D sublayerTransform;
-
-
-
@property(nullable, strong) CALayer *mask;
-
-
-
@property BOOL masksToBounds;
-
-
-
- (CGPoint)convertPoint:(CGPoint)p fromLayer:(nullable CALayer *)l;
-
- (CGPoint)convertPoint:(CGPoint)p toLayer:(nullable CALayer *)l;
-
- (CGRect)convertRect:(CGRect)r fromLayer:(nullable CALayer *)l;
-
- (CGRect)convertRect:(CGRect)r toLayer:(nullable CALayer *)l;
-
-
-
- (CFTimeInterval)convertTime:(CFTimeInterval)t fromLayer:(nullable CALayer *)l;
-
- (CFTimeInterval)convertTime:(CFTimeInterval)t toLayer:(nullable CALayer *)l;
-
-
-
-
-
-
- (nullable CALayer *)hitTest:(CGPoint)p;
-
-
-
- (BOOL)containsPoint:(CGPoint)p;
-
-
-
-
-
@property(nullable, strong) id contents;
-
-
-
@property CGRect contentsRect;
-
-
-
-
-
-
-
-
@property(copy) NSString *contentsGravity;
-
-
-
@property CGFloat contentsScale
-
-
-
@property CGRect contentsCenter;
-
-
-
@property(copy) NSString *minificationFilter;
-
-
-
@property(copy) NSString *magnificationFilter;
-
-
-
@property float minificationFilterBias;
-
-
-
@property(getter=isOpaque) BOOL opaque;
-
-
-
- (void)display;
-
-
-
- (void)setNeedsDisplay;
-
-
- (void)setNeedsDisplayInRect:(CGRect)r;
-
-
-
- (BOOL)needsDisplay;
-
-
-
- (void)displayIfNeeded;
-
-
-
@property BOOL needsDisplayOnBoundsChange;
-
-
-
@property BOOL drawsAsynchronously
-
-
-
- (void)drawInContext:(CGContextRef)ctx;
-
- (void)renderInContext:(CGContextRef)ctx;
-
-
-
@property CAEdgeAntialiasingMask edgeAntialiasingMask;
-
-
-
@property BOOL allowsEdgeAntialiasing;
-
-
-
@property(nullable) CGColorRef backgroundColor;
-
-
-
@property CGFloat cornerRadius;
-
-
-
@property CGFloat borderWidth;
-
-
-
@property(nullable) CGColorRef borderColor;
-
-
-
@property float opacity;
-
-
-
@property BOOL allowsGroupOpacity;
-
-
@property(nullable, strong) id compositingFilter;
-
-
@property(nullable, copy) NSArray *filters;
-
-
@property(nullable, copy) NSArray *backgroundFilters;
-
-
@property BOOL shouldRasterize;
-
-
@property CGFloat rasterizationScale;
-
-
-
-
@property(nullable) CGColorRef shadowColor;
-
-
-
@property float shadowOpacity;
-
-
-
@property CGSize shadowOffset;
-
-
-
@property CGFloat shadowRadius;
-
-
-
@property(nullable) CGPathRef shadowPath;
-
-
-
- (CGSize)preferredFrameSize;
-
-
- (void)setNeedsLayout;
-
-
- (BOOL)needsLayout;
-
-
- (void)layoutIfNeeded;
-
-
- (void)layoutSublayers;
-
-
-
+ (nullable id<CAAction>)defaultActionForKey:(NSString *)event;
-
-
- (nullable id<CAAction>)actionForKey:(NSString *)event;
-
-
@property(nullable, copy) NSDictionary<NSString *, id<CAAction>> *actions;
-
-
-
-
-
- (void)addAnimation:(CAAnimation *)anim forKey:(nullable NSString *)key;
-
-
-
- (void)removeAllAnimations;
-
-
-
- (void)removeAnimationForKey:(NSString *)key;
-
-
-
- (nullable NSArray<NSString *> *)animationKeys;
-
-
-
- (nullable CAAnimation *)animationForKey:(NSString *)key;
-
-
-
-
-
-
@property(nullable, copy) NSString *name;
-
-
-
@property(nullable, weak) id delegate;
-
-
@property(nullable, copy) NSDictionary *style;
-
@end
-
-
-
@protocol CAAction
-
-
-
-
-
-
-
- (void)runActionForKey:(NSString *)event object:(id)anObject
-
arguments:(nullable NSDictionary *)dict;
-
@end
-
-
-
@interface NSNull (CAActionAdditions) <CAAction>
-
-
@end
-
-
-
-
@interface NSObject (CALayerDelegate)
-
-
- (void)displayLayer:(CALayer *)layer;
-
-
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
-
-
- (void)layoutSublayersOfLayer:(CALayer *)layer;
-
-
- (nullable id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event;
-
@end
-
-
-
-
CA_EXTERN NSString * const kCAGravityCenter
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
CA_EXTERN NSString * const kCAGravityTop
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
CA_EXTERN NSString * const kCAGravityBottom
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
CA_EXTERN NSString * const kCAGravityLeft
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
CA_EXTERN NSString * const kCAGravityRight
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
CA_EXTERN NSString * const kCAGravityTopLeft
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
CA_EXTERN NSString * const kCAGravityTopRight
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
CA_EXTERN NSString * const kCAGravityBottomLeft
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
CA_EXTERN NSString * const kCAGravityBottomRight
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
-
CA_EXTERN NSString * const kCAGravityResize
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
CA_EXTERN NSString * const kCAGravityResizeAspect
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
CA_EXTERN NSString * const kCAGravityResizeAspectFill
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
-
-
-
CA_EXTERN NSString * const kCAFilterNearest
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
-
CA_EXTERN NSString * const kCAFilterLinear
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
-
CA_EXTERN NSString * const kCAFilterTrilinear
-
__OSX_AVAILABLE_STARTING (__MAC_10_6, __IPHONE_3_0);
-
-
-
CA_EXTERN NSString * const kCAOnOrderIn
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
CA_EXTERN NSString * const kCAOnOrderOut
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
-
-
-
CA_EXTERN NSString * const kCATransition
-
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
-
-
NS_ASSUME_NONNULL_END
-
-
@end
四、CALayer的簡單使用
1.CALayer是被定義在QuartzCore框架中的,因此要想使用CALayer,先導入QuartzCore框架(如果已經導入了UIKit框架,就無需導入QuartzCore框架,因爲UIKit本身已經引入QuartzCore框架 )
1> 點擊項目名稱,然後點擊右邊TARGETS下面的target
2> 點擊Build Pases後,展開Link Binary....,添加 + 號
3> 在搜索框中輸入"Quartz",選中QuartzCore.framework,最後add添加
4> 添加完畢後,這個框架就會出現在項目文件夾中
如果你覺得位置不好看,還可以將它拖到Frameworks文件夾下,跟其他框架放一起
2.在項目代碼中導入QuartzCore框架的主頭文件
-
#import <QuartzCore/QuartzCore.h>
3.通過CALayer修改UIImageView的界面屬性
你也可以使用UIButton或者UILabel,這裏就以UIImageView爲例子
1> 先創建一個UIImageView,添加到控制器的view中
-
UIImage *image = [UIImage imageNamed:@"lufy.png"];
-
UIImageView *imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
-
imageView.center = CGPointMake(100, 100);
-
[self.view addSubview:imageView];
2> 設置陰影
-
imageView.layer.shadowColor = [UIColor grayColor].CGColor;
-
imageView.layer.shadowOffset = CGSizeMake(10, 10);
-
imageView.layer.shadowOpacity = 0.5;<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"
* 第1行設置陰影的顏色爲灰色,注意,這裏使用的是UIColor的CGColor屬性,是一種CGColorRef類型的數據
* 第2行設置陰影的偏移大小,可以看出陰影往原圖的右下角偏移
* 第3行設置陰影的不透明度爲0.5,表示半透明。如果爲1,代表完全不透明。
3> 設置圓角大小
通過layer屬性可以訪問視圖內部的CALayer對象
-
imageView.layer.cornerRadius = 10;
-
imageView.layer.masksToBounds = YES;
* 第1行設置圓角半徑爲10
* 第2行的maskToBounds=YES:可以看做是強制內部的所有子層支持圓角效果,少了這個設置,UIImageView是不會有圓角效果的
* 注意,如果設置了maskToBounds=YES,那將不會有陰影效果
4> 設置邊框寬度和顏色
-
imageView.layer.borderWidth = 5;
-
imageView.layer.borderColor = [UIColor redColor].CGColor;
* 第1行設置邊框寬度爲5
* 第2行設置邊框顏色爲紅色
5> 設置旋轉
-
imageView.layer.transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);
* 利用transform屬性可以設置旋轉、縮放等效果
* M_PI_4表示四分之π,順時針旋轉45°
* 後面的(0, 0, 1)表示Z軸這個向量,修改這個向量可以做一些三維旋轉效果,你可以隨便改個值試一下,比如(1, 1, 1)
* 總體的意思是layer會繞着Z軸順時針旋轉45°,也就是在x、y平面進行旋轉
第二部分:創建新的層
一、添加一個簡單的圖層
-
CALayer *myLayer = [CALayer layer];
-
-
myLayer.bounds = CGRectMake(0, 0, 100, 100);
-
-
myLayer.position = CGPointMake(100, 100);
-
-
myLayer.backgroundColor = [UIColor redColor].CGColor;
-
-
myLayer.cornerRadius = 10;
-
-
[self.view.layer addSublayer:myLayer];
* 第1行創建了一個自動釋放的CALayer對象,你也可以使用經典的alloc和init方法來創建
* 第12行將創建好的層添加到控制器的view的層中
二、添加一個顯示圖片的圖層
-
CALayer *myLayer = [CALayer layer];
-
/ 設置層的寬度和高度(100x100)
-
myLayer.bounds = CGRectMake(0, 0, 100, 100);
-
/ 設置層的位置
-
myLayer.position = CGPointMake(100, 100);
-
/ 設置需要顯示的圖片
-
myLayer.contents = (id)[UIImage imageNamed:@"lufy.png"].CGImage;
-
/ 設置層的圓角半徑爲10
-
myLayer.cornerRadius = 10;
-
/ 如果設置了圖片,需要設置這個屬性爲YES纔有圓角效果
-
myLayer.masksToBounds = YES;
-
/ 添加myLayer到控制器的view的layer中
-
[self.view.layer addSublayer:myLayer];
* 在第7行設置需要顯示的圖片,注意,這裏用的是UIImage的CGImage屬性,是一種CGImageRef類型的數據
三、爲什麼CALayer中使用CGColorRef和CGImageRef這2種數據類型,而不用UIColor和UIImage?
* 首先要知道:CALayer是定義在QuartzCore框架中的;CGImageRef、CGColorRef兩種數據類型是定義在CoreGraphics框架中的;UIColor、UIImage是定義在UIKit框架中的
* 其次,QuartzCore框架和CoreGraphics框架是可以跨平臺使用的,在iOS和Mac OS X上都能使用,但是UIKit只能在iOS中使用
* 因此,爲了保證可移植性,QuartzCore不能使用UIImage、UIColor,只能使用CGImageRef、CGColorRef
* 不過很多情況下,可以通過UIKit對象的特定方法,得到CoreGraphics對象,比如UIImage的CGImage方法可以返回一個CGImageRef
四、UIView和CALayer的選擇
細心的朋友不難發現,其實前面的2個效果不僅可以通過添加層來實現,還可以通過添加UIView來實現。比如,第1個紅色的層可以用一個UIView來實現,第2個顯示圖片的層可以用一個UIImageView來實現。 既然CALayer和UIView都能實現相同的顯示效果,那究竟該選擇誰好呢?
* 其實,對比CALayer,UIView多了一個事件處理的功能。也就是說,CALayer不能處理用戶的觸摸事件,而UIView可以
* 所以,如果顯示出來的東西需要跟用戶進行交互的話,用UIView;如果不需要跟用戶進行交互,用UIView或者CALayer都可以
* 當然,CALayer的性能會高一些,因爲它少了事件處理的功能,更加輕量級
五、UIView和CALayer的其他關係
* UIView可以通過subviews屬性訪問所有的子視圖,類似地,CALayer也可以通過sublayers屬性訪問所有的子層
* UIView可以通過superview屬性訪問父視圖,類似地,CALayer也可以通過superlayer屬性訪問父層
* 下面再看一張UIView和CALayer的關係圖:
如果兩個UIView是父子關係,那麼它們內部的CALayer也是父子關係。
第三部分層的屬性
一、隱式動畫屬性
* 在前面幾講中已經提到,每一個UIView內部都默認關聯着一個CALayer,我們可用稱這個Layer爲Root Layer(根層)。所有的非Root Layer,也就是手動創建的CALayer對象,都存在着隱式動畫。
* 與UIView不同,CALayer實際上包含了一個表現層和一個模型層。模型層是用來在內存中存儲必要的圖層信息的。表現層則是用在將圖層顯示在屏幕上,併爲此做了相應的優化。
如果說一個動畫是隱式動畫,那就意味着用做動畫的屬性是在模型層中被修改的然後在通過表現層傳遞出來,並最終顯示在屏幕上。 如果動畫是顯示動畫,進行動畫的屬性就是隻存在於表現層的,而原始的模型層(在進行動畫之前的)會保持不變。這就意味着除非做其他的動作,否則在一個顯示動畫結束之後,CALayer會回到動畫開始之前的狀態,因爲下面的模型層並沒有被修改.
* 當對非Root Layer的部分屬性進行相應的修改時,默認會自動產生一些動畫效果,這些屬性稱爲Animatable Properties(可動畫屬性)。
* 列舉幾個常見的Animatable Properties:
bounds:用於設置CALayer的寬度和高度。修改這個屬性會產生縮放動畫
backgroundColor:用於設置CALayer的背景色。修改這個屬性會產生背景色的漸變動畫
position:用於設置CALayer的位置。修改這個屬性會產生平移動畫
比如:假設一開始CALayer的position爲(100, 100),然後在某個時刻修改爲(200, 200),那麼整個CALayer就會在短時間內從(100, 100)這個位置平移到(200, 200)
* 我們也可以從官方文檔中查詢所有的Animatable Properties
1.點擊Window -> Organizer
2.在搜索框輸入"animatable"即可
二、position和anchorPoint
* position和anchorPoint屬性都是CGPoint類型的
* position可以用來設置CALayer在父層中的位置,它是以父層的左上角爲座標原點(0, 0)
* anchorPoint稱爲"定位點",它決定着CALayer身上的哪個點會在position屬性所指的位置。它的x、y取值範圍都是0~1,默認值爲(0.5, 0.5)
1.創建一個CALayer,添加到控制器的view的layer中
-
CALayer *myLayer = [CALayer layer];
-
-
myLayer.bounds = CGRectMake(0, 0, 100, 100);
-
-
myLayer.position = CGPointMake(100, 100);
-
-
myLayer.backgroundColor = [UIColor redColor].CGColor;
-
-
[self.view.layer addSublayer:myLayer];
第5行設置了myLayer的position爲(100, 100),又因爲anchorPoint默認是(0.5, 0.5),所以最後的效果是:myLayer的中點會在父層的(100, 100)位置
注意,藍色線是我自己加上去的,方便大家理解,並不是默認的顯示效果。兩條藍色線的寬度均爲100。
2.若將anchorPoint改爲(0, 0),myLayer的左上角會在(100, 100)位置
-
myLayer.anchorPoint = CGPointMake(0, 0);
3.若將anchorPoint改爲(1, 1),myLayer的右下角會在(100, 100)位置
-
myLayer.anchorPoint = CGPointMake(1, 1);
4.將anchorPoint改爲(0, 1),myLayer的左下角會在(100, 100)位置
-
myLayer.anchorPoint = CGPointMake(0, 1);
我想,你應該已經明白anchorPoint的用途了吧,它決定着CALayer身上的哪個點會在position所指定的位置上。它的x、y取值範圍都是0~1,默認值爲(0.5, 0.5),因此,默認情況下,CALayer的中點會在position所指定的位置上。當anchorPoint爲其他值時,以此類推。
第四部分:自定義圖層
方法描述:創建一個CALayer的子類,然後覆蓋drawInContext:方法,使用Quartz2D API進行繪圖
創建一個CALayer的子類
2.在.m文件中覆蓋drawInContext:方法,在裏面繪圖
-
@implementation MJLayer
-
#pragma mark 繪製一個實心三角形
-
- (void)drawInContext:(CGContextRef)ctx {
-
-
CGContextSetRGBFillColor(ctx, 0, 0, 1, 1);
-
-
CGContextMoveToPoint(ctx, 50, 0);
-
-
CGContextAddLineToPoint(ctx, 0, 100);
-
-
CGContextAddLineToPoint(ctx, 100, 100);
-
-
CGContextClosePath(ctx);
-
-
CGContextFillPath(ctx);
-
}
-
@end
3.在控制器中添加圖層到屏幕上
-
MJLayer *layer = [MJLayer layer];
-
-
layer.bounds = CGRectMake(0, 0, 100, 100);
-
-
layer.position = CGPointMake(100, 100);
-
-
[layer setNeedsDisplay];
-
[self.view.layer addSublayer:layer];
注意第7行,需要調用setNeedsDisplay這個方法,纔會觸發drawInContext:方法的調用,然後進行繪圖
二、自定義層的方法2
方法描述:設置CALayer的delegate,然後讓delegate實現drawLayer:inContext:方法,當CALayer需要繪圖時,會調用delegate的drawLayer:inContext:方法進行繪圖。
* 這裏要注意的是:不能再將某個UIView設置爲CALayer的delegate,因爲UIView對象已經是它內部根層的delegate,再次設置爲其他層的delegate就會出問題。UIView和它內部CALayer的默認關係圖:
1.創建新的層,設置delegate,然後添加到控制器的view的layer中
-
CALayer *layer = [CALayer layer];
-
-
layer.delegate = self;
-
-
layer.bounds = CGRectMake(0, 0, 100, 100);
-
-
layer.position = CGPointMake(100, 100);
-
-
[layer setNeedsDisplay];
-
[self.view.layer addSublayer:layer];
* 在第3行設置了CALayer的delegate,這裏的self是指控制器
* 注意第9行,需要調用setNeedsDisplay這個方法,纔會通知delegate進行繪圖
2.讓CALayer的delegate(前面設置的是控制器)實現drawLayer:inContext:方法
-
#pragma mark 畫一個矩形框
-
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
-
-
CGContextSetRGBStrokeColor(ctx, 0, 0, 1, 1);
-
-
CGContextSetLineWidth(ctx, 10);
-
-
CGContextAddRect(ctx, layer.bounds);
-
-
CGContextStrokePath(ctx);
-
}
三、其他
1.總結
無論採取哪種方法來自定義層,都必須調用CALayer的setNeedsDisplay方法才能正常繪圖。
2.UIView的詳細顯示過程
* 當UIView需要顯示時,它內部的層會準備好一個CGContextRef(圖形上下文),然後調用delegate(這裏就是UIView)的drawLayer:inContext:方法,並且傳入已經準備好的CGContextRef對象。而UIView在drawLayer:inContext:方法中又會調用自己的drawRect:方法
* 平時在drawRect:中通過UIGraphicsGetCurrentContext()獲取的就是由層傳入的CGContextRef對象,在drawRect:中完成的所有繪圖都會填入層的CGContextRef中,然後被拷貝至屏幕
參考:
CALayer的簡單介紹
CALayer的使用
更多動畫知識:
iOS Core Animation: Advanced Techniques中文譯本