在CALayer上繪圖有2種方法ios
1)建立一個CALayer的子類,而後覆蓋drawInContext:方法,可使用Quartz2D api進行繪圖api
2)設置CALayer的代理,讓代理實現drawLayer:inContext方法進行繪圖。通常是在控制器裏實現。這樣會增長控制器的負擔。iview
調用這2個方法之後都必須調用setNeedsDisplay方法從新繪製視圖,才能生效。函數
全部的非root layer都存在隱式動畫,根圖層沒有隱式動畫。負責UIVIEW部分。視圖上的根圖層是沒有隱式動畫的。動畫
1)採用代理方式在圖層上繪圖的代碼ui
//atom
// MainViewController.mspa
// CALayer繪圖_demo1代理
//code
// Created by mac on 13-10-1.
// Copyright (c) 2013年 mac. All rights reserved.
//
#import "MainViewController.h"
#import <QuartzCore/QuartzCore.h>
@interfaceMainViewController ()
@end
@implementation MainViewController
- (void)viewDidLoad
{
[superviewDidLoad];
// Do any additional setup after loading the view.
// 建立一個layer
CALayer *mylayer = [CALayer layer];
[mylayer setBounds:CGRectMake(0, 0, 200, 200)];
[mylayer setBackgroundColor:[UIColorredColor].CGColor];
[mylayer setPosition:CGPointMake(100, 100)];
[self.view.layer addSublayer:mylayer];
// 這裏不能將代理設置成view,由於view已是根layer的代理,再設置一個圖層的代理,會由衝突。
// 一般讓控制器來充當代理。若是代理多個圖層,最好用一個標誌區分開,也能夠用tag來區分。
[mylayer setDelegate:self];
[mylayer setNeedsDisplay];
NSLog(@"%@",mylayer);
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
NSLog(@"%@",layer);
CGRect rect = CGRectMake(50, 50, 100, 100);
// 這2個方法都不起做用。不能使用uikit的方法
// [[UIColor blueColor] set];
// UIRectFill(rect);
// 在Core animation裏不能使用ui方法。
// QuartzCore是誇平臺的,這裏只能使用C語言的函數,不能使用UIKIT方法
CGContextSetRGBFillColor(ctx, 0, 1, 0, 1);
CGContextAddRect(ctx, rect);
CGContextDrawPath(ctx, kCGPathFill);
}
@end
顯示結果
2) 自定義CALayer類,重寫drawInContext方法來實現圖層繪圖
1.自定義layer,重寫drawInContext方法
#import "MyLayer.h"
#import <QuartzCore/QuartzCore.h>
@implementation MyLayer
// 從寫drawInContext方法是關鍵,不然不能實如今自定義圖層上繪圖
- (void)drawInContext:(CGContextRef)ctx
{
// 繪製圖層 繪製一個橢圓
// 這裏要用quartzcore方法,由於參數是CGContextRef,這個引用不能被uikit方法使用
CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 200));
CGContextSetRGBFillColor(ctx, 1, 0, 0, 1);
CGContextDrawPath(ctx, kCGPathFill);
}
@end
2.建立自定義視圖,在自定義視圖裏實例化layer
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
NSLog(@"init myview");
MyLayer *mylayer = [MyLayer layer];
// 要設置大小,不然不顯示
[mylayer setFrame:CGRectMake(0, 0, 100, 200)];
[self.layer addSublayer:mylayer];
[mylayer setNeedsDisplay];//添加到視圖根圖層之後,要調用本身的(圖層)的setneedsdisplay方法
self.mylayer = mylayer;
}
returnself;
}
3.在控制器根視圖裏建立自定義視圖
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
MyView *myview = [[MyView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
[myview setBackgroundColor:[UIColor lightGrayColor]];
[self.view addSubview:myview];
}
![](http://static.javashuo.com/static/loading.gif)
方法觸發順序
1.調用視圖的init方法
2.在init方法裏調用setneedsdisplay方法的時候,會觸發代理的drawlayer方法,在drawlayer方法裏要調用父類的drawlayer方法,這個會觸發視圖裏的drawinrect方法。
3.而後調用視圖的drawinrect方法
4.drawinrect方法再觸發調用圖層的drawincontext方法。
順序
1)父視圖的init方法
2)父視圖的代理方法
3)父視圖的drawinrect方法
4)子圖層的drawincontext方法
使用代理方式繪圖時,當uiview收到setneedsdisplay消息時,calayer會傳出來一個cgcontextref引用。這時候能夠在cgcontextref裏進行繪圖。
當使用自定義圖層方式繪圖時,當uiview收到setneedsdisplay消息時,uiview會調用本身的drawlayer方法,這個方法會調用本身的drawrect方法,這個方法再觸發子圖層的drawlayer方法。
繪製圖像
#import "MyLayer.h"
#import <QuartzCore/QuartzCore.h>
@implementation MyLayer
- (void)drawInContext:(CGContextRef)ctx
{
// 繪製圖層
CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 100));
CGContextSetRGBFillColor(ctx, 1, 0, 0, 1);
CGContextDrawPath(ctx, kCGPathFill);
// 繪製圖層
CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 100, 100));
CGContextSetRGBFillColor(ctx, 0, 1, 0, 1);
CGContextDrawPath(ctx, kCGPathFill);
UIImage *image = [UIImage imageNamed:@"頭像2.png"];
CGContextDrawImage(ctx, CGRectMake(50, 50, 100, 100), image.CGImage);
}
@end
結果
頭像是反的。
這時候用到形變座標系,但在形變座標系以前,應該保存cgcontextref,形變座標系以後,要恢復cgcontextref
//
#import "MyLayer.h"
#import <QuartzCore/QuartzCore.h>
@implementation MyLayer
- (void)drawInContext:(CGContextRef)ctx
{
// 繪製圖層
CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 100));
CGContextSetRGBFillColor(ctx, 1, 0, 0, 1);
CGContextDrawPath(ctx, kCGPathFill);
// 繪製圖層
CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 100, 100));
CGContextSetRGBFillColor(ctx, 0, 1, 0, 1);
CGContextDrawPath(ctx, kCGPathFill);
// 在形變座標系以前應該保存Context CGContextSaveGState(ctx);
// 應該先翻轉座標系,
// 不然會頭像是反的
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextTranslateCTM(ctx, 0, -self.bounds.size.height);
UIImage *image = [UIImage imageNamed:@"頭像2.png"];
CGContextDrawImage(ctx, CGRectMake(50, 50, 100, 100), image.CGImage);
// 在形變座標系以後要恢復context 這樣不會影響之後的繪圖 CGContextRestoreGState(ctx);
}
在uiview裏添加了自定義圖層之後,若是在圖層裏繪圖,則uiview裏自己的drawrect裏的繪圖會執行,可是會子圖層的顯示給覆蓋掉
//
// MyView.m
// CALayer自定義視圖實現圖層繪圖
//
// Created by mac on 13-10-2.
// Copyright (c) 2013年 mac. All rights reserved.
//
#import "MyView.h"
#import "MyLayer.h"
@interface MyView ()
@property (nonatomic,weak) MyLayer *mylayer;
@end
@implementation MyView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
NSLog(@"init myview");
MyLayer *mylayer = [MyLayer layer];
[mylayer setBounds:self.bounds];
[mylayer setPosition:CGPointMake(100, 100)];
[self.layer addSublayer:mylayer];
[mylayer setNeedsDisplay];
self.mylayer = mylayer;
}
return self;
}
// 這個代碼是執行的,可是結果會被子圖層的顯示給覆蓋掉
- (void)drawRect:(CGRect)rect { // Drawing code CGContextRef context = UIGraphicsGetCurrentContext(); CGContextAddRect(context, CGRectMake(50, 50, 20, 20)); CGContextDrawPath(context, kCGPathFill); }
@end
若是使用了calayer的繪圖就不要再使用視圖的drawrect的繪圖方法,即便用了,也會被layer的繪圖顯示給覆蓋掉。CGContextRef是位圖的上下文。動畫就是把全部的圖層和到一個CGContextRef,位圖上下文裏。提升動畫執行效率。ios的動畫效果好,就是把全部的圖層合成一個位圖來執行,這樣的效果會好。