Quartz2D
Quartz2D概述
- Quartz2D可以完成什么:
- 繪制圖形:線,三角形,圓,橢圓等等
- 繪制文字(在image上)
- 繪制\生成圖片
- 繪制\生成PDF
- 剪裁\切割圖片
- 自定義UI控件
- 手勢解鎖
- 什么是圖形上下文(Graphics Context):
- 是一個CGContextRef類型的數(shù)據(jù)
- 保存繪制的信息和狀態(tài)(我們也可以理解成是一個畫布,在這個畫布上繪制)
- 決定繪制的輸出目標(繪制到什么地方去?)(輸出目標可以是PDF文件芭碍、Bitmap或者顯示器的窗口上)
- Quartz2D可以獲取到的圖形上下文
- Bitmap Graphics Context
- PDF Graphics Context
- Window Graphics Context
- Layer Graphics Context
- Printer Graphics Context
Quartz2D對于圖形的應(yīng)用
Quartz2D的基本用法
- 在Quartz2D中蘋果為我們提供了一套CoreGraphics框架,這是一套c語言的框架,下面的前兩種方式就是采用這套,最后一種方式是在前面方式的基礎(chǔ)上在OC中封裝的一個類
- 無論是哪個方法,都必須在drawRect方法中執(zhí)行,因為在drawRect方法中才能獲取上下文
CGPath繪制
//CGPath繪制
- (void)CGPath
{
//獲取圖形上下文
CGContextRef ref = UIGraphicsGetCurrentContext();
//初始化一條線路
CGMutablePathRef pathref = CGPathCreateMutable();
//設(shè)置起點
//1.路徑 2.旋轉(zhuǎn),縮放,平移等 3.起點的x軸坐標 4.起點的y軸坐標
CGPathMoveToPoint(pathref, nil, 10, 10);
//設(shè)置終點
CGPathAddLineToPoint(pathref, nil, 100, 100);
//把這個路線放到上下文上
//1.上下文 2.路徑
CGContextAddPath(ref, pathref);
//釋放路徑(凡是c語言函數(shù)中帶create,copy,一樣要釋放)
CGPathRelease(pathref);
//繪制
CGContextStrokePath(ref);
//填充
// CGContextFillPath(ref);
}
CGContexRef繪制
//CGContexRef繪制
- (void)CGContext
{
//獲取圖形上下文
CGContextRef ref = UIGraphicsGetCurrentContext();
// 設(shè)置起點
CGContextMoveToPoint(ref, 10, 10);
//設(shè)置終點(第一條線)
CGContextAddLineToPoint(ref, 100, 100);
//設(shè)置終點(第二條線)
CGContextAddLineToPoint(ref, 10, 100);
//設(shè)置線冒
CGContextSetLineCap(ref, kCGLineCapRound);
//設(shè)置拐角
CGContextSetLineJoin(ref, kCGLineJoinRound);
//設(shè)置線寬
CGContextSetLineWidth(ref, 10.0f);
//閉合
CGContextClosePath(ref);
//設(shè)置線的顏色
CGContextSetStrokeColorWithColor(ref, [UIColor redColor].CGColor);
//設(shè)置填充顏色
CGContextSetFillColorWithColor(ref, [UIColor yellowColor].CGColor);
//下面兩個誰在前面執(zhí)行那個
// //填充
// CGContextFillPath(ref);
// //繪制
// CGContextStrokePath(ref);
//由于上面兩個方法只有一個能執(zhí)行,所以為了兩個都有效果,采用下面的方法,兩個都設(shè)置(枚舉)
CGContextDrawPath(ref, kCGPathFillStroke);
}
UIBezierPath的基本用法
//貝瑟爾基本用法
- (void)bezier
{
//初始化
UIBezierPath *path = [[UIBezierPath alloc] init];
//設(shè)置起點
[path moveToPoint:CGPointMake(10, 10)];
//設(shè)置終點(一條線)
[path addLineToPoint:CGPointMake(100, 100)];
//設(shè)置終點(第二條線)
[path addLineToPoint:CGPointMake(10, 100)];
//設(shè)置線寬
[path setLineWidth:10.0f];
//設(shè)直線冒
[path setLineCapStyle:kCGLineCapRound];
//設(shè)置拐角(兩條線才能有拐角)
[path setLineJoinStyle:kCGLineJoinRound];
//設(shè)直線的顏色
[[UIColor redColor] setStroke];
//設(shè)置填充顏色
[[UIColor yellowColor] setFill];
//閉合路徑
[path closePath];
//填充
[path fill];
//繪制
[path stroke];
}
//利用貝瑟爾繪制圓,橢圓和扇形
- (void)drawRound
{
//繪制圓
UIBezierPath *path = [UIBezierPath bezierPath];
// 1.圓心 2.半徑 3. 開始的值(PI/ 2) 4. 結(jié)束的值 5. yes: 逆時針繪制 no:順時針
[path addArcWithCenter:CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2) radius:100 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
//繪制
[path stroke];
//繪制橢圓
UIBezierPath *path1 = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 100, 50)];
//繪制
[path1 stroke];
//扇形
UIBezierPath *path2 =[[UIBezierPath alloc] init];
//設(shè)置起點
[path2 moveToPoint:CGPointMake(100, 100)];
[path2 addArcWithCenter:CGPointMake(100, 100) radius:100 startAngle:0 endAngle:M_PI / 2 clockwise:YES];
//閉合
[path2 closePath];
//繪制
[path2 stroke];
}
自定義View
- 如何利用Quartz2D繪制東西到view上徒役?
- 首先孽尽,得有圖形上下文,因為它能保存繪圖信息忧勿,并且決定著繪制到什么地方去
- 其次杉女,那個圖形上下文必須跟view相關(guān)聯(lián),才能將內(nèi)容繪制到view上面
- 自定義view的步驟
- 新建一個類鸳吸,繼承自UIView
- 實現(xiàn)- (void)drawRect:(CGRect)rect方法熏挎,然后在這個方法中
- 取得跟當(dāng)前view相關(guān)聯(lián)的圖形上下文
- 繪制相應(yīng)的圖形內(nèi)容
- 利用圖形上下文將繪制的所有內(nèi)容渲染顯示到view上面
- 注意:drawRect方法在view第一次顯示到屏幕上會調(diào)用,在ViewDidLoad之后,viewWillAppear之前,如果想要在改變圖形上下文之后調(diào)用drawRect方法顯示改變后的效果,用setNeedsDisplay方法,調(diào)用完setNeedsDisplay方法之后,drawRect會被調(diào)用一次
繪制餅狀圖
- 基本思路:可以封裝一個類繼承與UIView,也可以給UIView寫一個分類,這里采用繼承
//在外部留好接口:傳入數(shù)據(jù)和餅狀圖劃分的顏色,以數(shù)組形式傳入
@interface NewView : UIView
/** 數(shù)字數(shù)組 */
@property (nonatomic,strong) NSMutableArray *numberArray;
/** 顏色數(shù)組 */
@property (nonatomic,strong) NSMutableArray *colorArray;
/** 圓心 */
@property (nonatomic,assign) CGPoint centerPoint;
@end
//在.m中的drawRect方法中繪制
- (void)drawRect:(CGRect)rect {
//繪制圓
CGContextRef ref = UIGraphicsGetCurrentContext();
//設(shè)置圓心
CGPoint centerPoint = self.centerPoint;
//設(shè)置一個半徑
CGFloat radius = 100;
//設(shè)置起始點
CGFloat starAngle = - M_PI_2;
//計算總和
CGFloat total = 0;
for (NSNumber *num in self.numberArray) {
total = total + [num floatValue];
}
//從頭開始一個一個繪制,利用for循環(huán)
for (int i = 0; i < self.numberArray.count; i++) {
//計算百分比
CGFloat per = [self.numberArray[i] floatValue] / total ;
//設(shè)置終點
CGFloat endAngle = starAngle + 2 * M_PI * per;
//設(shè)置圓心為起點
CGContextMoveToPoint(ref,centerPoint.x , centerPoint.y);
//添加一條圓弧
CGContextAddArc(ref, centerPoint.x, centerPoint.y, radius, starAngle, endAngle, NO);
//閉合
CGContextClosePath(ref);
//設(shè)置填充顏色
CGContextSetFillColorWithColor(ref, [(UIColor *)self.colorArray[i] CGColor]);
//繪制
CGContextDrawPath(ref, kCGPathFillStroke);
//重置起點
starAngle = endAngle;
}
}
利用貝瑟爾曲線繪制曲線
- (void)drawRect:(CGRect)rect {
// Drawing code
//二元
UIBezierPath *path =[[UIBezierPath alloc] init];
//設(shè)置起點
[path moveToPoint:CGPointMake(10, 10)];
//設(shè)置曲線的屬性
//參數(shù)1.曲線的終點,2.曲線的基準點
[path addQuadCurveToPoint:CGPointMake(100,100) controlPoint:CGPointMake(50, 100)];
//繪制
[path stroke];
// 三元
UIBezierPath *path = [[UIBezierPath alloc] init];
//設(shè)置起點
[path moveToPoint:CGPointMake(10, 100)];
//參數(shù)1.曲線的終點 2.曲線的第一個基準點 3.曲線的第二個基準點
[path addCurveToPoint:CGPointMake(100, 100) controlPoint1:CGPointMake(35, 25) controlPoint2:CGPointMake(75, 175)];
//繪制
[path stroke];
}
Quartz2D對于圖片的應(yīng)用
- 對于圖片來說獲取上下文可以不需要在drawRect中,有自己的獲取方式
- 獲取圖片的上下文一定在 UIGraphicsBeginImageContext(),UIGraphicsEndImageContext()這兩個方法中寫,或者進行對圖片的裁剪,旋轉(zhuǎn),擦除等等.
- 操作完圖片之后可以用UIGraphicsGetImageFromCurrentImageContext()方法獲得修改完之后的圖片
- 除了圖片可以這樣修改,PDF格式也提供了類似的方法
根據(jù)顏色生成圖片
- 實現(xiàn)原理:先獲取一個固定大小的上下文,根據(jù)傳進來的顏色,將上下文顏色填充,在image上平鋪,輸出image
//根據(jù)顏色生成圖片
- (UIImage *)getImageWithColor:(UIColor *)color
{
//開始
// 1.圖片的尺寸,2.是否是不透明的,3.圖片的縮放比例
UIGraphicsBeginImageContext(CGSizeMake(200, 50));
//獲取上下文
CGContextRef ref = UIGraphicsGetCurrentContext();
//設(shè)置顏色
CGContextSetFillColorWithColor(ref, color.CGColor);
//設(shè)置填充區(qū)域
CGContextFillRect(ref, CGRectMake(0, 0, 100, 100));
//填充
CGContextDrawPath(ref, kCGPathFillStroke);
//獲取圖片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
//結(jié)束
UIGraphicsEndImageContext();
//輸出圖片
return image;
}
圖片的剪裁
//圖片的裁剪
- (UIImage *)clipWithImage:(UIImage *)image
{
//獲取上下文(并給出這個上下文的尺寸)
UIGraphicsBeginImageContext(CGSizeMake(image.size.width / 2.0, image.size.height));
//這里的rect是值得在image的什么區(qū)域去繪制(下面這個寫其實是繪制在整個image中)
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
//結(jié)束
UIGraphicsEndImageContext();
//輸出圖片
return UIGraphicsGetImageFromCurrentImageContext();
}
切圓
- 實現(xiàn)原理:先畫出一個圓型的上下文,再講圖片畫到畫布上
//切圓
- (UIImage *)clipWithimage:(UIImage *)image
{
UIGraphicsBeginImageContext(image.size);
//獲取上下文
CGContextRef ref = UIGraphicsGetCurrentContext();
//畫圓
CGContextAddArc(ref, image.size.width / 2.0, image.size.height / 2.0, image.size.height / 2.0, 0, M_PI * 2, NO);
//裁剪畫布
CGContextClip(ref);
// 把圖片畫到畫布上
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
//結(jié)束
UIGraphicsEndImageContext();
//輸出并返回
return UIGraphicsGetImageFromCurrentImageContext();
}
圖片旋轉(zhuǎn),平移,縮放
//圖片旋轉(zhuǎn)
- (UIImage *)transWithImage:(UIImage *)image
{
UIGraphicsBeginImageContext(image.size);
//獲取上下文
CGContextRef ref = UIGraphicsGetCurrentContext();
//縮放(旋轉(zhuǎn)縮放平移是在上下文操作圖片)
CGContextScaleCTM(ref, 0.6, 0.6);
//平移
CGContextTranslateCTM(ref, 50, 0);
//旋轉(zhuǎn) 1.上下文 2.角度
CGContextRotateCTM(ref, M_PI_4);
//把圖片畫到畫布上
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
//結(jié)束
UIGraphicsEndImageContext();
//返回繪制的圖片
return UIGraphicsGetImageFromCurrentImageContext();
}
圖片擦除(刮獎原理)(截屏也用到了這個的核心原理)
- 實現(xiàn)原理:當(dāng)手指觸摸到屏幕上的時候,去到觸摸的某一個點,放大成一個正方形或者圓形,形成橡皮的感覺,在滑動過的區(qū)域?qū)D片刮除,顯示下面的label或者其他view,一定要保證刮除的我圖片一定是透明的,否則看不到下面的label或者view
- (void)viewDidLoad {
[super viewDidLoad];
//初始化要顯示在下面的提示label
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 200, 50)];
label.textAlignment = NSTextAlignmentCenter;
label.text = @"恭喜您中獎了";
[self.view addSubview:label];
//初始化顯示在上面的imageview(用上面的根據(jù)顏色生成圖片方法生成一個灰色的圖層,看起來像一種刮獎的圖層)
self.imageView = [[UIImageView alloc] initWithImage:[self getImageWithColor:[UIColor grayColor]]];
self.imageView.frame = CGRectMake(100, 100, 200, 50);
[self.view addSubview:self.imageView];
}
//刮獎()
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = touches.anyObject;
CGPoint point = [touch locationInView:self.imageView];
//滑塊區(qū)域(觸碰到的點放大成正方形)
CGRect rect = CGRectMake( point.x - 10,point.y - 10, 20, 20);
//獲取上下文(這里記得一定要透明)
UIGraphicsBeginImageContextWithOptions(self.imageView.bounds.size, NO, 0);
CGContextRef ref = UIGraphicsGetCurrentContext();
//把imageView的layer映射到上下文中(這個是核心,由于UIView本質(zhì)上顯示東西的layer層,所以實質(zhì)是將imageView顯示的東西全部復(fù)制給上下文,app中長用到的截屏就利用了這個原理)
[self.imageView.layer renderInContext:ref];
//清除劃過的區(qū)域
CGContextClearRect(ref, rect);
UIImage *image =UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//返回圖片并不斷的傳給UIImageView上去顯示
self.imageView.image = image;
}
繪制文字(以圖片的形式輸出)(給圖片右下角繪制專屬的唯一標示(也就是水印)就用到了這個原理)
//繪制文字
- (UIImage *)drawWithStr:(NSString *)str
{
//獲取上下文
UIGraphicsBeginImageContext(self.view.frame.size);
//利用富文本設(shè)置文字的屬性
NSDictionary *dic = @{NSFontAttributeName:[UIFont systemFontOfSize:14.0f],NSForegroundColorAttributeName:[UIColor redColor]};
//繪制在上下文中
[str drawInRect:CGRectMake(10, 10, 200, 100) withAttributes:dic];
//輸出image
return UIGraphicsGetImageFromCurrentImageContext();
}