引言
在iOS動(dòng)畫篇:核心動(dòng)畫中講到如何給一個(gè)視圖添加動(dòng)畫效果仑荐,但是其僅局限在系統(tǒng)控件的具有動(dòng)畫效果的屬性雕拼。假設(shè)現(xiàn)在我們要做一個(gè)空心圓形的進(jìn)度條,隨著進(jìn)度的變化具有對(duì)應(yīng)的動(dòng)畫效果粘招,這時(shí)候就需要去自定義一個(gè)圓形的View啥寇,并實(shí)現(xiàn)其形狀隨進(jìn)度屬性的變化而變化,使用Quartz2D就可以輕松滿足此需求洒扎。
什么是Quartz2D
Quartz2D是iOS和OSX中的一個(gè)二維繪圖引擎辑甜,這組API具有許多強(qiáng)大的功能,如:圖形的繪制袍冷、透明層磷醋、陰影、顏色管理胡诗、反鋸齒邓线、PDF文檔的管理等等淌友。
本文主要介紹了Quartz2D主要相關(guān)概念,描述其中的圖形繪制部分(通過路徑繪制圖形)骇陈,以實(shí)現(xiàn)自定義View震庭。本文不對(duì)Quartz2D的基礎(chǔ)過多提及,如果讀者需要更深入了解Quartz2D你雌,可以Google"Quartz2D編程指南"研讀Quartz2D系列譯文器联。
相關(guān)概念
使用Quartz2D來繪制圖形,需要知道的相關(guān)概念:
1匪蝙、Core Graphics
Core Graphic是一套基于C的框架主籍,用于一切繪圖操作,UIKit就是基于Core Graphic實(shí)現(xiàn)的逛球,因此它可以實(shí)現(xiàn)比UIKit更底層的功能千元。
Core Graphic使用Quartz2D作為繪圖引擎,因此Quartz2D其實(shí)是Core Graphic的一部分颤绕,這兩個(gè)名詞密不可分幸海。
2、圖形上下文
畫畫需要畫布奥务,Core Graphics工作是的“畫布”就是圖形上下文物独,它決定圖形繪制成什么樣子,并繪制到哪里去氯葬。在“畫布”中挡篓,每個(gè)連續(xù)的繪制操作都可以看成添加一個(gè)“圖層”到畫布上,在運(yùn)行中我們可以通過額外的繪制操作來疊加更多“圖層”來形成復(fù)雜的圖形帚称。
推薦使用UIView自動(dòng)為我們準(zhǔn)備好的圖形上下文官研,因?yàn)樽远x上下文會(huì)降低內(nèi)存的使用效率,導(dǎo)致性能下降闯睹。當(dāng)需要我們調(diào)用UIGraphicsGetCurrentContext()來獲取圖形上下文戏羽。
3、路徑
相信很多人都臨摹過書法楼吃,在一張薄薄的紙上照著書法家的筆跡來書寫始花,這個(gè)“筆跡”就可以看成路徑,通過確定的路徑孩锡,可以確定繪圖的形狀酷宵、渲染的區(qū)域等等。
通過創(chuàng)建路徑并加入到上下文中渲染就能繪制出想要的圖形躬窜。
創(chuàng)建路徑有以下三種方式:
1.使用CGContextRef創(chuàng)建忧吟,如CGContextAddArc
這種方式是直接對(duì)圖形上下文進(jìn)行操作,常用的方法有:
CGContextBeginPath //開始畫路徑
CGContextMoveToPoint //移動(dòng)到某一點(diǎn)
CGContexAddLineToPoint //畫直線
CGContexAddCurveToPoint //畫餅圖
CGContexAddEllipseInRect //畫橢圓
CGContexAddArc //畫圓
CGContexAddRect //畫方框
CGContexClosePath //封閉當(dāng)前路徑
2.使用CGPathRef創(chuàng)建斩披,如CGPathAddArc
使用方法一繪制路徑后將清空?qǐng)D形上下文溜族,如果我們想保存路徑來復(fù)用,可以使用Quartz提供的CGPath函數(shù)集合來創(chuàng)建可復(fù)用的路徑對(duì)象垦沉。
常用的函數(shù)如下:
CGPathCreateMutable
CGPathMoveToPoint
CGPathAddLineToPoint
CGPathAddCurveToPoint
CGPathAddEllipseInRect
CGPathAddArc
CGPathAddRect
CGPathCloseSubpath
這些函數(shù)和上面方法一的一一對(duì)應(yīng)煌抒,可代替之使用。
CGContextAddPath:添加一個(gè)新的路徑
2.使用UIBezierPath創(chuàng)建厕倍,如bezierPathWithOvalInRect
UIBezierPath存在于UIKit中寡壮,是對(duì)路徑繪制的封裝,和CGContextRef類似讹弯,優(yōu)點(diǎn)是更面向?qū)ο罂黾龋覀兛梢韵癫僮髌胀▽?duì)象一樣對(duì)其進(jìn)行操作。
在自定義View的時(shí)候组民,一般使用UIBezierPath來創(chuàng)建路徑就能基本滿足我們的需求棒仍,推薦使用。
UIBezierPath的常用方法如下:
@property(nonatomic) CGFloat lineWidth; //線的寬度
@property(nonatomic) CGLineCap lineCapStyle; //起點(diǎn)和終點(diǎn)樣式
@property(nonatomic) CGLineJoin lineJoinStyle; //轉(zhuǎn)角樣式
//創(chuàng)建path
+ (instancetype)bezierPath;
//矩形
+ (instancetype)bezierPathWithRect:(CGRect)rect;
//以矩形框?yàn)榍芯€畫圓
+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect;
//帶圓角的矩形框
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius; // rounds all corners with the same horizontal and vertical radius
//畫圓弧
+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;
//移動(dòng)到某一點(diǎn)
- (void)moveToPoint:(CGPoint)point;
//添加直線
- (void)addLineToPoint:(CGPoint)point;
//帶一個(gè)基準(zhǔn)點(diǎn)的曲線
- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
//帶兩個(gè)基準(zhǔn)點(diǎn)的曲線
- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;
//封閉路徑
- (void)closePath;
//添加新的路徑
- (void)appendPath:(UIBezierPath *)bezierPath;
//渲染
- (void)fill;
- (void)stroke;
4臭胜、渲染
繪畫的最后一步莫其,它之于繪圖的意義如畫畫的最后上顏料一樣。
渲染分為兩種方式:
∷嗜1)填充Fill:將路徑內(nèi)部填充渲染
÷叶浮2)描邊Stroke:不填充,只對(duì)路徑進(jìn)行渲染
5仪壮、繪圖狀態(tài)棧
圖形上下文包含一個(gè)繪圖狀態(tài)棧憨颠,默認(rèn)為空。
』1)保存圖形狀態(tài)時(shí)爽彤,將創(chuàng)建當(dāng)前圖形狀態(tài)的一個(gè)副本并入棧。
》Ψ小2)還原圖形狀態(tài)時(shí)淫茵,將棧頂?shù)膱D形狀態(tài)推出棧并替換當(dāng)前圖形狀態(tài)。
使用:調(diào)用CGContextSaveGState來保存蹬跃,CGContextRestoreGState來還原匙瘪。
繪圖的核心步驟
在view上繪制一個(gè)圖形的方式有很多種,表現(xiàn)形式可能不一樣蝶缀,但其實(shí)質(zhì)步驟都是一樣的:
1)獲取上下文
2)繪制路徑
3)添加路徑到上下文
4)修改圖形狀態(tài)參數(shù)
5)渲染上下文
下面我們以畫一個(gè)圓形來演示其實(shí)現(xiàn)步驟:
1)使用CGContextRef創(chuàng)建路徑
//獲取上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//繪制路徑: 圓形(中心坐標(biāo)200丹喻、200、半徑100翁都、起點(diǎn)弧度0碍论、終點(diǎn)弧度2PI、畫的方向0逆1正)
CGContextAddArc(ctx, 200, 200, 100, 0, M_PI * 2, 0);
//修改圖形狀態(tài)參數(shù)
CGContextSetRGBStrokeColor(ctx, 0.5, 0.5, 0.9, 1.0);//筆顏色
CGContextSetLineWidth(ctx, 10);//線條寬度
//渲染上下文
CGContextStrokePath(ctx);
2)使用CGPathRef創(chuàng)建路徑
//獲取上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//創(chuàng)建可變路徑
CGMutablePathRef path = CGPathCreateMutable();
//添加圓形到路徑中(所在路徑柄慰、不進(jìn)行變換操作鳍悠、中心坐標(biāo)200税娜、200、起點(diǎn)弧度0藏研、終點(diǎn)弧度2PI敬矩、畫的方向0逆1正)
CGPathAddArc(path, NULL, 200, 200, 100, 0, M_PI * 2, 1);
//將路徑添加到上下文
CGContextAddPath(ctx, path);
//修改圖形狀態(tài)參數(shù)
CGContextSetRGBStrokeColor(ctx, 0.5, 0.5, 0.9, 1.0);//筆顏色
CGContextSetLineWidth(ctx, 10);//線條寬度
//渲染上下文
CGContextStrokePath(ctx);
3)使用UIBezierPath創(chuàng)建路徑
//創(chuàng)建路徑
UIBezierPath * path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 200, 200)];
//修改圖形狀態(tài)參數(shù)
[[UIColor colorWithRed:0.5 green:0.5 blue:0.9 alpha:1.0] setStroke];//筆顏色
[path setLineWidth:10];//線條寬度
//渲染
[path stroke];
以上三種方式都可以實(shí)現(xiàn)繪制,通過比較我們可以發(fā)現(xiàn)使用UIBezierPath創(chuàng)建路徑的形式是最簡潔且最直觀的蠢挡,推薦使用UIBezierPath弧岳,在以后的動(dòng)畫中我們也將更多地應(yīng)用UIBezierPath到動(dòng)畫的實(shí)現(xiàn)中。
自定義view的步驟
只需簡單兩步即可:
步驟一:新建一個(gè)類业踏,繼承UIView類禽炬。
步驟二:重載drawRect方法,在這個(gè)方法中進(jìn)行繪圖勤家。
以自定義一個(gè)圓形View為例:
1)新建CircleView類腹尖,繼承UIView類
2)在CircleView.m中重載drawRect方法
- (void)drawRect:(CGRect)rect {
}
3)畫一個(gè)圓
- (void)drawRect:(CGRect)rect {
UIBezierPath * path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 200, 200)];
[[UIColor colorWithRed:0.5 green:0.5 blue:0.9 alpha:1.0] setStroke];
[path setLineWidth:10];
[path stroke];
}
4)創(chuàng)建CircleView的實(shí)例添加到視圖中
- (void)viewDidLoad {
[super viewDidLoad];
CircleView * cricleView = [[CircleView alloc]initWithFrame:self.view.bounds];
[self.view addSubview:cricleView];
}
5)效果圖
成功畫了一個(gè)圓形,現(xiàn)在只差怎樣讓它“動(dòng)起來”了却紧!
思考
1桐臊、Quartz2D的坐標(biāo)系和UIView的坐標(biāo)系有什么不同?
2晓殊、繪制圖形時(shí)不同路徑使用不同的狀態(tài)參數(shù)渲染需要怎樣操作断凶?
3、怎樣使用CALayer來自定義View巫俺?
next:
如何在自定義View上實(shí)現(xiàn)動(dòng)畫效果