首页 > 代码库 > 008-Quartz2D
008-Quartz2D
掌握
• 1.基本概念
问题一:什么是Quartz2D?
问题三:什么是图形上下文?
(输出目标可以是PDF文件、Bitmap或者显示器的窗口上)
• 2.基本绘图的实现
问题一:为什么要实现drawRect:方法才能绘图到view上,该方法在什么时候被调用?
问题二:如何利用Quartz2D自定义view?(自定义UI控件)
问题三:如何利用代码实现Quartz2D绘图三部曲?
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(ctx, 10, 10); // 起始点CGContextAddLineToPoint(ctx, 100, 100); // 添加一根线段直到这个点
CGContextStrokePath(ctx); // CGContextFillPath(ctx);
问题四:绘图顺序?
问题五:常见图形拼接路径函数
void CGContextMoveToPoint(CGContextRef c, CGFloat x, CGFloat y)
void CGContextAddLineToPoint(CGContextRef c, CGFloat x, CGFloat y)
void CGContextAddRect(CGContextRef c, CGRect rect)
void CGContextAddEllipseInRect(CGContextRef context, CGRect rect)
void CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y,
CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)
void CGContextDrawPath(CGContextRef c, CGPathDrawingMode mode)
void CGContextStrokePath(CGContextRef c)
void CGContextFillPath(CGContextRef c)
提示:一般以CGContextDraw、CGContextStroke、CGContextFill开头的函数,都是用来绘制路径的
问题六:常见的操作
1.图形上下文栈的操作
void CGContextSaveGState(CGContextRef c)
void CGContextRestoreGState(CGContextRef c)
2.矩阵操作
void CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy)
void CGContextRotateCTM(CGContextRef c, CGFloat angle)
void CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty)
问题七:实用功能
1.图片水印
void UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale)
UIImage* UIGraphicsGetImageFromCurrentImageContext();
void UIGraphicsEndImageContext();
#import "UIImage+WHB.h"@implementation UIImage (WHB)+ (instancetype)waterImageWithBg:(NSString *)bg logo:(NSString *)logo{ UIImage *bgImage = [UIImage imageNamed:bg]; // 1.创建一个基于位图的上下文(开启一个基于位图的上下文) UIGraphicsBeginImageContextWithOptions(bgImage.size, NO, 0.0); // 2.画背景 [bgImage drawInRect:CGRectMake(0, 0, bgImage.size.width, bgImage.size.height)]; // 3.画右下角的水印 UIImage *waterImage = [UIImage imageNamed:logo]; CGFloat scale = 0.2; CGFloat margin = 5; CGFloat waterW = waterImage.size.width * scale; CGFloat waterH = waterImage.size.height * scale; CGFloat waterX = bgImage.size.width - waterW - margin; CGFloat waterY = bgImage.size.height - waterH - margin; [waterImage drawInRect:CGRectMake(waterX, waterY, waterW, waterH)]; // 4.从上下文中取得制作完毕的UIImage对象 UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); // 5.结束上下文 UIGraphicsEndImageContext(); return newImage;}@end
// 将image对象压缩为PNG格式的二进制数据 NSData *data =http://www.mamicode.com/ UIImagePNGRepresentation(newImage); // UIImageJPEGRepresentation(<#UIImage *image#>, <#CGFloat compressionQuality#>) // 写入文件 NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"new.png"]; [data writeToFile:path atomically:YES];
2.图片裁剪
void CGContextClip(CGContextRef c)
将当前上下所绘制的路径裁剪出来(超出这个裁剪区域的都不能显示)
•图片裁剪代码实例:
#import "UIImage+WHB.h"@implementation UIImage (WHB)+ (instancetype)circleImageWithName:(NSString *)name borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor{ // 1.加载原图 UIImage *oldImage = [UIImage imageNamed:name]; // 2.开启上下文 CGFloat imageW = oldImage.size.width + 2 * borderWidth; CGFloat imageH = oldImage.size.height + 2 * borderWidth; CGSize imageSize = CGSizeMake(imageW, imageH); UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0); // 3.取得当前的上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 4.画边框(大圆) [borderColor set]; CGFloat bigRadius = imageW * 0.5; // 大圆半径 CGFloat centerX = bigRadius; // 圆心 CGFloat centerY = bigRadius; CGContextAddArc(ctx, centerX, centerY, bigRadius, 0, M_PI * 2, 0); CGContextFillPath(ctx); // 画圆 // 5.小圆 CGFloat smallRadius = bigRadius - borderWidth; CGContextAddArc(ctx, centerX, centerY, smallRadius, 0, M_PI * 2, 0); // 裁剪(后面画的东西才会受裁剪的影响) CGContextClip(ctx); // 6.画图 [oldImage drawInRect:CGRectMake(borderWidth, borderWidth, oldImage.size.width, oldImage.size.height)]; // 7.取图 UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); // 8.结束上下文 UIGraphicsEndImageContext(); return newImage;}@end
3.屏幕截图
核心代码
- (void)renderInContext:(CGContextRef)ctx;
调用某个view的layer的renderInContext:方法即可
•屏幕截图代码实例:
@implementation UIImage (WHB)+ (instancetype)captureWithView:(UIView *)view{ // 1.开启上下文 UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, 0.0); // 2.将控制器view的layer渲染到上下文 [view.layer renderInContext:UIGraphicsGetCurrentContext()]; // 3.取出图片 UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); // 4.结束上下文 UIGraphicsEndImageContext(); return newImage;}@end
- (IBAction)clip { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 1.捕捉 UIImage *newImage = [UIImage captureWithView:self.view]; // 2.写文件 NSData *data =http://www.mamicode.com/ UIImagePNGRepresentation(newImage); NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"new.png"]; [data writeToFile:path atomically:YES]; });}
ps:条纹背景
#import "WHBViewController.h"@interface WHBViewController ()@property (weak, nonatomic) IBOutlet UITextView *textView;@end@implementation WHBViewController- (void)viewDidLoad{ [super viewDidLoad]; // 1.创建一行背景图片 CGFloat rowW = self.view.frame.size.width;// CGFloat rowH = 40; CGFloat rowH = 30; UIGraphicsBeginImageContextWithOptions(CGSizeMake(rowW, rowH), NO, 0.0); CGContextRef ctx = UIGraphicsGetCurrentContext(); // 画矩形框 [[UIColor redColor] set]; CGContextAddRect(ctx, CGRectMake(0, 0, rowW, rowH)); CGContextFillPath(ctx); // 2.画线 [[UIColor greenColor] set]; CGFloat lineWidth = 2; CGContextSetLineWidth(ctx, lineWidth); CGFloat dividerX = 0; CGFloat dividerY = rowH - lineWidth; CGContextMoveToPoint(ctx, dividerX, dividerY); CGContextAddLineToPoint(ctx, rowW - dividerX, dividerY); CGContextStrokePath(ctx); // 3.取图 UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); // 4.结束上下文 UIGraphicsEndImageContext(); // 5.设置为背景 self.textView.backgroundColor = [UIColor colorWithPatternImage:newImage];}- (void)imageBg{ UIImage *oldImage = [UIImage imageNamed:@"me"]; UIGraphicsBeginImageContextWithOptions(self.view.frame.size, NO, 0.0); [oldImage drawInRect:self.view.bounds]; UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); self.view.backgroundColor = [UIColor colorWithPatternImage:newImage];}@end
• 3.代码示例
画线条: 图形效果:
- (void)drawRect:(CGRect)rect{ // Drawing code // 1.获得图形上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.拼接图形(路径) // 设置线段宽度 CGContextSetLineWidth(ctx, 10); // 设置线段头尾部的样式 CGContextSetLineCap(ctx, kCGLineCapRound); // 设置线段转折点的样式 CGContextSetLineJoin(ctx, kCGLineJoinRound); /** 第1根线段 **/ // 设置颜色 CGContextSetRGBStrokeColor(ctx, 1, 0, 0, 1); // 设置一个起点 CGContextMoveToPoint(ctx, 10, 10); // 添加一条线段到(100, 100) CGContextAddLineToPoint(ctx, 100, 100); // 渲染一次 CGContextStrokePath(ctx); /** 第2根线段 **/ // 设置颜色 CGContextSetRGBStrokeColor(ctx, 0, 0, 1, 1); // 设置一个起点 CGContextMoveToPoint(ctx, 200, 190); // 添加一条线段到(150, 40) CGContextAddLineToPoint(ctx, 150, 40); CGContextAddLineToPoint(ctx, 120, 60); // 3.渲染显示到view上面 CGContextStrokePath(ctx);}
画三角形:
/** * 画三角形 */void drawTriangle(){ // 1.获得上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.画三角形 CGContextMoveToPoint(ctx, 0, 0); CGContextAddLineToPoint(ctx, 100, 100); CGContextAddLineToPoint(ctx, 150, 80); // 关闭路径(连接起点和最后一个点) CGContextClosePath(ctx); CGContextSetRGBStrokeColor(ctx, 0, 1, 0, 1); // 3.绘制图形 CGContextStrokePath(ctx);}
画矩形:
/** * 画四边形 */void draw4Rect(){ // 1.获得上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.画矩形 CGContextAddRect(ctx, CGRectMake(10, 10, 150, 100)); // set : 同时设置为实心和空心颜色 // setStroke : 设置空心颜色 // setFill : 设置实心颜色 [[UIColor whiteColor] set]; // CGContextSetRGBFillColor(ctx, 0, 0, 1, 1); // 3.绘制图形 CGContextFillPath(ctx);}
画圆:
/** * 画圆 */void drawCircle(){ // 1.获得上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.画圆 CGContextAddEllipseInRect(ctx, CGRectMake(50, 10, 100, 100)); CGContextSetLineWidth(ctx, 10); // 3.显示所绘制的东西 CGContextStrokePath(ctx);}
/** * 在view第一次显示到屏幕上的时候会调用一次 */- (void)drawRect:(CGRect)rect{ // 1.获得上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.画1/4圆 CGContextMoveToPoint(ctx, 100, 100); CGContextAddLineToPoint(ctx, 100, 150); CGContextAddArc(ctx, 100, 100, 50, -M_PI_2, M_PI, 1); CGContextClosePath(ctx); [[UIColor redColor] set]; // 3.显示所绘制的东西 CGContextFillPath(ctx);}
画圆弧:
自定义ImageView:
- (void)drawRect:(CGRect)rect{ drawImage();}void drawImage(){ // 1.取得图片 UIImage *image = [UIImage imageNamed:@"me"]; // 2.画// [image drawAtPoint:CGPointMake(50, 50)];// [image drawInRect:CGRectMake(0, 0, 150, 150)]; [image drawAsPatternInRect:CGRectMake(0, 0, 200, 200)]; // 3.画文字 NSString *str = @"为xxx所画"; [str drawInRect:CGRectMake(0, 180, 100, 30) withAttributes:nil];}/** * 画文字 */void drawText(){ // 1.获得上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.画矩形 CGRect cubeRect = CGRectMake(50, 50, 100, 100); CGContextAddRect(ctx, cubeRect); // 3.显示所绘制的东西 CGContextFillPath(ctx); // 4.画文字 NSString *str = @"哈哈哈哈Good morning hello hi hi hi hi"; // [str drawAtPoint:CGPointZero withAttributes:nil]; NSMutableDictionary *attrs = [NSMutableDictionary dictionary]; // NSForegroundColorAttributeName : 文字颜色 // NSFontAttributeName : 字体 attrs[NSForegroundColorAttributeName] = [UIColor redColor]; attrs[NSFontAttributeName] = [UIFont systemFontOfSize:50]; [str drawInRect:cubeRect withAttributes:attrs];}
图形上下文栈: 图形效果:
- (void)drawRect:(CGRect)rect{ // 1.获得上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 将ctx拷贝一份放到栈中 CGContextSaveGState(ctx); // 设置绘图状态 CGContextSetLineWidth(ctx, 10); [[UIColor redColor] set]; CGContextSetLineCap(ctx, kCGLineCapRound); // 第1根线 CGContextMoveToPoint(ctx, 50, 50); CGContextAddLineToPoint(ctx, 120, 190); CGContextStrokePath(ctx); // 将栈顶的上下文出栈,替换当前的上下文 CGContextRestoreGState(ctx); // 第2根线 CGContextMoveToPoint(ctx, 10, 70); CGContextAddLineToPoint(ctx, 220, 290); CGContextStrokePath(ctx);// CGContextDrawPath(ctx, kCGPathStroke);}
矩阵操作:
/** 渐变色 虚线 pattern blend ..... ..... 阴影 */- (void)drawRect:(CGRect)rect{ CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextSaveGState(ctx); CGContextRotateCTM(ctx, M_PI_4 * 0.4); CGContextScaleCTM(ctx, 0.5, 0.5); CGContextTranslateCTM(ctx, 0, 150); CGContextAddRect(ctx, CGRectMake(10, 10, 50, 50)); CGContextStrokePath(ctx); CGContextRestoreGState(ctx); CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 100, 100)); CGContextMoveToPoint(ctx, 100, 100); CGContextAddLineToPoint(ctx, 200, 250); // 矩阵操作// CGContextScaleCTM(ctx, 0.5, 0.5); CGContextStrokePath(ctx);}
裁剪:
- (void)drawRect:(CGRect)rect{ CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextSaveGState(ctx); // 0.画圆 CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 100, 100)); // 裁剪圆形区域 CGContextClip(ctx); CGContextFillPath(ctx); // 1.显示图片 UIImage *image = [UIImage imageNamed:@"me"]; [image drawAtPoint:CGPointMake(100, 100)]; CGContextRestoreGState(ctx); CGContextAddRect(ctx, CGRectMake(0, 0, 100, 100)); CGContextFillPath(ctx);}
重绘: 图形效果:
@interface MJViewController ()- (IBAction)sizeChange:(UISlider *)sender;@property (weak, nonatomic) IBOutlet View *circleView;@end@implementation MJViewController- (IBAction)sizeChange:(UISlider *)sender { self.circleView.radius = sender.value;}@end
#import <UIKit/UIKit.h>@interface MJView : UIView/** * 圆的半径 */@property (nonatomic, assign) float radius;@end
#import "View.h"@implementation View- (void)setRadius:(float)radius{ _radius = radius; // 重绘显示到屏幕上 [self setNeedsDisplay];}/** * 默认只会在view第一次显示的时候调用(只能由系统自动调用, 不能手动调用) */- (void)drawRect:(CGRect)rect{ NSLog(@"drwract---%f", self.radius); CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextAddArc(ctx, 125, 125, self.radius, 0, M_PI * 2, 0); CGContextFillPath(ctx);}@end
动画:
#import "SnowView.h"@interface SnowView()@property (nonatomic, assign) CGFloat snowY;@end@implementation SnowView- (void)awakeFromNib{ CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)]; [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; // [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(setNeedsDisplay) userInfo:nil repeats:YES];}- (void)drawRect:(CGRect)rect{ self.snowY+=5; if (self.snowY >= rect.size.height) { self.snowY = -100; } UIImage *image = [UIImage imageNamed:@"snow.jpg"]; [image drawAtPoint:CGPointMake(0, self.snowY)];}