图形上下文对象绘制图形
注:手动重新绘制上下文时调用 [$view drawRect:$rect]是没有用的
需要调用[$view setNeedsDisplay]
-(void)drawRect:(CGRect)rect{
//// ---普通绘制
// CGContextRef ctx =UIGraphicsGetCurrentContext();
//
//// 设置路径
// UIBezierPath *path = [UIBezierPath bezierPath];
// [path moveToPoint:CGPointMake(100, 100)];
// [path addQuadCurveToPoint:CGPointMake(200, 100) controlPoint:CGPointMake(150, 0)];
//
//// 设置上下文画笔属性
// CGContextSetLineJoin(ctx, kCGLineJoinRound);
// [[UIColor purpleColor] set];
//
//// 添加路径到上下文
// CGContextAddPath(ctx, path.CGPath);
//// 绘制路径
// CGContextFillPath(ctx);
// ---精简绘制
// 绘制椭圆 根据高宽来绘制椭圆
// UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 50, 100, 50)];
// 绘制圆角矩形
// UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(100, 50, 100, 100) cornerRadius:20];
// 绘制弧形 center中心 radius半径 startAngle开始角度 endAngle结束消毒 clockwise是否顺时针画
// UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 50) radius:25 startAngle:M_PI endAngle:0 clockwise:YES];
// [[UIColor purpleColor] set];
// [path fill];
}
注意:在重绘图形是定时器需要使用CADisplayLink而不是NSTimer
//因为 [$view setNeedsDisplay]方法不是立即执行 而是等待屏幕刷新时才执行drawRect方法进行绘制
//所以NSTimer和屏幕刷新时间不一致会导致偏差时间越来越多导致卡顿 而CADisplayLink是在屏幕刷新时调用 所以与drawRect同步执行
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
保存图形上下文状态到图形上下文栈
CGContextSaveGState(ctx);
CGContextRestoreGState(ctx);
在设置画笔颜色等属性后添加上路径后绘制另一条路径时可能有需求恢复之前的上下文状态 可以使用CGContextRestoreGState(ctx)恢复
CGContextRef ctx = UIGraphicsGetCurrentContext();
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointZero];
[path addQuadCurveToPoint:CGPointMake(100, 150) controlPoint:CGPointMake(150, 0)];
CGContextSetLineWidth(ctx, 2);
[[UIColor purpleColor] set];
//保存当前宽度为2 颜色为紫色的状态
CGContextSaveGState(ctx);
CGContextAddPath(ctx, path.CGPath);
CGContextStrokePath(ctx);
//修改颜色为灰色
[[UIColor grayColor] set];
path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 100, 50)];
[path stroke];
//恢复颜色为紫色 宽度为2
CGContextRestoreGState(ctx);
path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(100, 100)];
[path addLineToPoint:CGPointMake(180, 180)];
CGContextAddPath(ctx, path.CGPath);
CGContextStrokePath(ctx);
CGContextXXXCTM图形绘制的矩阵操作
[[UIColor grayColor] set];
path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-50, -50, 100, 50)];
// 平移
CGContextTranslateCTM(ctx, 50, 50);
// 缩放
CGContextScaleCTM(ctx, 0.5, 0.5);
// 旋转
CGContextRotateCTM(ctx, M_PI_2);
//必须在图形绘制之前调用矩阵操作
CGContextAddPath(ctx, path.CGPath);
CGContextStrokePath(ctx);
UIGraphicsImageContext绘制图片
UIImage *image = [UIImage imageNamed:@"timg"];
//开始绘制图片上下文
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
// 获取上下文后可以开始绘制
[image drawAtPoint:CGPointZero];
[@"@Vijay" drawAtPoint:CGPointMake(image.size.width - 150, image.size.height - 60) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:30 ],NSForegroundColorAttributeName:[UIColor whiteColor]}];
// 从上下文中拿到绘制的图片
image = UIGraphicsGetImageFromCurrentImageContext();
// 关闭上下文
UIGraphicsEndImageContext();
UIImageView* uv = [[UIImageView alloc] initWithImage:image];
uv.contentMode = UIViewContentModeScaleAspectFit;
uv.frame = self.bounds;
[self addSubview:uv];
裁剪圆形图片[ path addClip]
UIImage *image = [UIImage imageNamed:@"timg"];
// 获取上下文后可以开始绘制
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
CGSize imageSize = image.size;
CGFloat radius = imageSize.width>imageSize.height?imageSize.height:imageSize.width;
//创建裁剪区域
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(imageSize.width/2 - radius/2, 0,radius, radius)];
// 添加裁剪区域
[path addClip];
[image drawAtPoint:CGPointZero];
[@"@Vijay" drawAtPoint:CGPointMake(image.size.width - 150, image.size.height - 60) withAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Arial-BoldMT" size:30],NSForegroundColorAttributeName:[UIColor redColor]}];
// 从上下文中拿到绘制的图片
image = UIGraphicsGetImageFromCurrentImageContext();
// 关闭上下文
UIGraphicsEndImageContext();
UIImageView* uv = [[UIImageView alloc] initWithImage:image];
uv.contentMode = UIViewContentModeScaleAspectFit;
uv.frame = self.bounds;
[self addSubview:uv];
截屏
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);
CGContextRef ctx= UIGraphicsGetCurrentContext();
// 所有view都有layer 所有view都是用layer画到上下文上的
[self.view.layer renderInContext:ctx];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// 转成二进制流
NSData* data = UIImagePNGRepresentation(image);
// 输出二进制流
[data writeToFile:@"/Users/jiewang/Documents/image.png" atomically:YES];
图片裁剪
@interface ViewController (){
CGPoint beginP;
}
@property (weak, nonatomic) IBOutlet UIImageView *imageV;
@property (strong,nonatomic) UIView *clipView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (UIView *)clipView{
if (_clipView == nil) {
UIView* uv = [[UIView alloc] init];
_clipView = uv;
uv.backgroundColor = [UIColor blackColor];
uv.alpha = 0.5;
[self.view addSubview:uv];
}
return _clipView;
}
- (IBAction)move:(UIPanGestureRecognizer *)sender {
// 手势开始
if (sender.state == UIGestureRecognizerStateBegan) {
beginP = [sender locationInView:sender.view];
// 手势变化
}else if (sender.state == UIGestureRecognizerStateChanged){
CGPoint curP = [sender translationInView:sender.view];
NSLog(@"%@",NSStringFromCGPoint(curP));
self.clipView.frame = CGRectMake(beginP.x, beginP.y, curP.x, curP.y);
// 手势结束
}else if (sender.state == UIGestureRecognizerStateEnded){
UIGraphicsBeginImageContextWithOptions(_imageV.bounds.size, NO, 0);
CGContextRef ctx= UIGraphicsGetCurrentContext();
UIBezierPath *path = [UIBezierPath bezierPathWithRect:_clipView.frame];
// 先要创建裁剪区域 再绘制图片
[path addClip];
[_imageV.layer renderInContext:ctx];
// 生成的图片大小取决于上下文大小 所以不imageview不会变小
_imageV.image = UIGraphicsGetImageFromCurrentImageContext();
[_clipView removeFromSuperview];
UIGraphicsEndImageContext();
}
}
擦除绘制区域内容
CGContextClearRect(ctx, rect);
系统宏剪裁图片(推荐)
- (UIImage*)clipImage:(UIImage*)image ByIndex:(CGFloat)index AndTotal:(CGFloat)total{
// 注意 CGImageCreateWithImageInRect底层是用的c操作的是像素点 但是我们用imagenamed加载的是@2x图
// 所以此处处理图片时需要获取屏幕像素比 来扩大剪裁像素范围
CGFloat scale = [[UIScreen mainScreen] scale];
CGFloat width = image.size.width/total *scale;
CGFloat height = image.size.height *scale;
CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, CGRectMake(index*width, 0, width, height));
// 注意 返回的图片也是2倍像素的 当使用时需要缩放0.5倍
return [UIImage imageWithCGImage:imageRef];}
绘制剪裁雪碧图
- (UIImage*)clipImage:(UIImage*)image ByIndex:(CGFloat)index AndTotal:(CGFloat)total{
CGFloat width = image.size.width/total;
CGFloat height = image.size.height;
// 设置需要生成的图片大小 为雪碧图中的某一个图
UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, height), NO, 0);
// 需要先设置裁剪区域 裁剪彩有效
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, width, height)];
[path addClip];
// 设置整张雪碧图的坐标x轴进行负偏移 已剪裁出当前需要的图片
[image drawAtPoint:CGPointMake(-index*width, 0)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}