一、- (void)drawRect:(CGRect)rect {}方法专门用来绘图
1.画直线
//作用:专门用来绘图
//什么时候调用:当View显示时调用
//参数:当前View的bounds
- (void)drawRect:(CGRect)rect {
[self drawLine];
}
- (void)drawLine {
//1.获取当前跟View相关联的上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//2.描述路径
UIBezierPath *path = [UIBezierPath bezierPath];
//一个路径可以描述多条线/
//2.1设置起点
//坐标原点是以当前绘制View的左上角为(0,0)
[path moveToPoint:CGPointMake(50, 50)];
//2.2添加一根线到某个点
[path addLineToPoint:CGPointMake(150, 150)];
[path moveToPoint:CGPointMake(100, 50)];
[path addLineToPoint:CGPointMake(150, 250)];
//把上一路径的终点做为下一个路径的起点
[path addLineToPoint:CGPointMake(250, 50)];
//设置上下文的状态
//设置线宽度
CGContextSetLineWidth(ctx, 10);
//设置上下文的连接样式
CGContextSetLineJoin(ctx, kCGLineJoinBevel);
//设置顶角样式
CGContextSetLineCap(ctx, kCGLineCapRound);
//设置线的颜色
//setStroke setFill
//如果直接使用set,会自动匹配渲染的模式.
[[UIColor redColor] set];
//3.把路径添加到上下文
CGContextAddPath(ctx, path.CGPath);
//4.把上下文的当中绘制的所有路径渲染View相关联的layer当中.
//渲染的方式有两种:
//描边:stroke
//填充:fill
CGContextStrokePath(ctx);
}
2、画曲线
image.png
#import "DrawView.h"
@implementation DrawView
-(void)awakeFromNib{
[super awakeFromNib];
}
-(void)drawRect:(CGRect)rect{
//画直线
// [self drawLine];
//画曲线
[self drawCurveLine];
}
//2.画曲线
-(void)drawCurveLine{
//1、获取上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//2、描述路径
UIBezierPath *path = [UIBezierPath bezierPath];
//画曲线
[path moveToPoint:CGPointMake(50, 250)];
//添加一根曲线到某个点
[path addQuadCurveToPoint:CGPointMake(250, 250) controlPoint:CGPointMake(50, 50)];
//3.把路径添加到上下文
CGContextAddPath(ctx, path.CGPath);
//4.把上下文的内容渲染到View的layer;
CGContextStrokePath(ctx);
}
@end
3、画矩形、圆角矩形
2.1矩形
2.2圆角矩形
2.3圆
#import "DrawView.h"
@implementation DrawView
-(void)awakeFromNib{
[super awakeFromNib];
}
-(void)drawRect:(CGRect)rect{
//1.画直线
// [self drawLine];
//2.画曲线
// [self drawCurveLine];
//3.画矩形、圆角矩形
[self drawShape];
}
-(void)drawShape{
//在此方法内部会自动创建 一个跟View相关联的上下文
//可以直接获取
//无论是开启上下文,还是获取上下文,都是以UIGraphics
//1.获取上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//2.描述路径
//2.1、描述矩形路径
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 50, 200, 100)];
//描述圆角矩形
//cornerRadius:圆角半径,如果圆角半径是宽和高的1/2,就变成圆了。
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 200, 200) cornerRadius:30];
//3.把路径添加到上下文
CGContextAddPath(ctx, path.CGPath);
//设置上下文的状态,必须得要在渲染之前设置.
[[UIColor yellowColor] set];
//4.把上下文的内容渲染到View的layer;
//CGContextStrokePath(ctx);
//填充
CGContextFillPath(ctx);
}
@end
4.画椭圆
#import "DrawView.h"
@implementation DrawView
-(void)awakeFromNib{
[super awakeFromNib];
}
-(void)drawRect:(CGRect)rect{
//1.画直线
// [self drawLine];
//2.画曲线
// [self drawCurveLine];
//3.画矩形、圆角矩形
// [self drawShape];
//4.画椭圆
[self drawOval];
}
//4.画椭圆
-(void)drawOval{
/**drawRect:底层实现原理
在drawRect:方法中会自动的创建一下4步:
1.获取上下文
2.描述路径
3.把路径添加到上下文
4.把上下文的内容渲染到View的layer
我们只需要描述路径就行了,一下几部会自动帮我们实现
*/
//如果宽度和高度设置为一样就变成了圆
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 200, 100)];
[[UIColor redColor] set];
[path stroke];
}
@end
5、画弧和扇形
-
画弧
画弧
#import "DrawView.h"
@implementation DrawView
-(void)awakeFromNib{
[super awakeFromNib];
}
-(void)drawRect:(CGRect)rect{
//5.画弧
//Center:弧所在圆的圆心
//radius:弧所在圆的半径
//startAngle:开始角度 ;0度是在圆的最右侧,向上,度数是负的,向下,度数是正的.
//endAngle:截至角度 (哪个位置)
//clockwise:是否为顺时针 (怎么样到这个位置)
CGPoint center = CGPointMake(rect.size.width*0.5, rect.size.height*0.5);
CGFloat radius = rect.size.width*0.5 - 10;
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:-M_PI clockwise:YES];
[path stroke];
}
- 画扇形
#import "DrawView.h"
@implementation DrawView
-(void)awakeFromNib{
[super awakeFromNib];
}
-(void)drawRect:(CGRect)rect{
//1.画直线
// [self drawLine];
//2.画曲线
// [self drawCurveLine];
//3.画矩形、圆角矩形
// [self drawShape];
//4.画椭圆
// [self drawOval];
//5.画弧
//Center:弧所在圆的圆心
//radius:弧所在圆的半径
//startAngle:开始角度 ;0度是在圆的最右侧,向上,度数是负的,向下,度数是正的.
//endAngle:截至角度 (哪个位置)
//clockwise:是否为顺时针 (怎么样到这个位置)
CGPoint center = CGPointMake(rect.size.width*0.5, rect.size.height*0.5);
CGFloat radius = rect.size.width*0.5 - 10;
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:-M_PI clockwise:YES];
//在弧的基础上添加一根线到圆心,然后关闭路径就变成了扇形
[path addLineToPoint:center];
//关闭路径(从路径的终点连接一根到到路径的起点)
[path closePath];
[path fill]; //当使用填充时,会自动关闭路径
}
6.下载进度条(重绘)
重绘
#import "ViewController.h"
#import "ProgressView.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *valueLabel;
@property (weak, nonatomic) IBOutlet ProgressView *progressView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)valueChange:(UISlider *)sender {
self.valueLabel.text = [NSString stringWithFormat:@"%.2f%%",sender.value * 100];
NSLog(@"%f",sender.value);
self.progressView.progressValue = sender.value;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
#import "ProgressView.h"
@implementation ProgressView
- (void)setProgressValue:(CGFloat)progressValue {
_progressValue = progressValue;
//[self drawRect:self.bounds];
//当系统调用drawRect方法时 在drawRect:内部会自动创建跟View相关联的上下文
//手动调用,是不会创建上下文.
//通知系统,调用drawRect
//重绘
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
// Drawing code
CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5);
CGFloat radius = rect.size.width * 0.5 - 10;
CGFloat startA = -M_PI_2;
CGFloat endA = startA + self.progressValue * M_PI * 2;
//1.获取跟View相关联的上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//2.描述路径
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
[path addLineToPoint:center];
//3.把路径添加到上下文
CGContextAddPath(ctx, path.CGPath);
[[UIColor colorWithWhite:1 alpha:0.5] set];
//4.把上下文的内容渲染的View上
CGContextFillPath(ctx);
}
@end
7.画文字
画文字
#import "DrawView.h"
@implementation DrawView
- (void)awakeFromNib {
[super awakeFromNib];
}
- (void)drawRect:(CGRect)rect {
//画文字
[self drawText:rect];
}
- (void)drawText :(CGRect )rect{
//画文字
NSString *text = @"小码哥小码哥小码哥小码哥";
//withAttributes
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
//设置字体
dict[NSFontAttributeName] = [UIFont systemFontOfSize:30];
//设置颜色
dict[NSForegroundColorAttributeName] = [UIColor redColor];
//设置描边
dict[NSStrokeColorAttributeName] = [UIColor blueColor];
dict[NSStrokeWidthAttributeName] = @3;
//设置阴影
NSShadow *shadow = [[NSShadow alloc] init];
shadow.shadowColor = [UIColor greenColor];
//设置阴影的偏移量
shadow.shadowOffset = CGSizeMake(10, 10);
dict[NSShadowAttributeName] = shadow;
//drawAtPoint:不会换行
//drawInRect:会自动换行
//在往View绘制过程中,如果绘制的内容超过View大小, 是不显示的.
// [text drawAtPoint:CGPointZero withAttributes:dict];
[text drawInRect:rect withAttributes:dict];
}
@end
8.画图片
画图片
#import "DrawView.h"
@implementation DrawView
- (void)awakeFromNib {
[super awakeFromNib];
}
- (void)drawRect:(CGRect)rect {
//1.加载图片
UIImage *image = [UIImage imageNamed:@"001"];
//drawAtPoint:绘制的是原始图片的尺寸大小.
// [image drawAtPoint:CGPointZero];
//把图片填充到指定的区域
// [image drawInRect:rect];
//设置一个裁剪区域(超过裁剪区域以外的内容全部裁剪掉)
// UIRectClip(CGRectMake(0, 0, 100, 50));
//把图片平铺到指定的区域
[image drawAsPatternInRect:rect];
[[UIColor redColor] set];
UIRectFill(CGRectMake(50, 50, 100, 100));
}
@end
二、上下文状态栈
-
第一种
图1
#import "DrawView.h"
@implementation DrawView
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef ctx = UIGraphicsGetCurrentContext();
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(20, 150)];
[path addLineToPoint:CGPointMake(280, 150)];
CGContextAddPath(ctx, path.CGPath);
//1.把当前上下文的状态保存到上下文状态栈
CGContextSaveGState(ctx);
CGContextSetLineWidth(ctx, 10);
[[UIColor redColor] set];
//取出上下文当中所有绘制的路径
//把上下文当中的状态应用到所有路径当中.
CGContextStrokePath(ctx);
UIBezierPath *path2 = [UIBezierPath bezierPath];
[path2 moveToPoint:CGPointMake(150, 20)];
[path2 addLineToPoint:CGPointMake(150, 280)];
CGContextAddPath(ctx, path2.CGPath);
//CGContextSetLineWidth(ctx, 1);
//[[UIColor blackColor] set];
//从上下文状态栈中取出状态
//从当前的上下文状态栈中取出栈顶的状态,覆盖掉当前的上下文状态
CGContextRestoreGState(ctx);
//取出上下文当中所有绘制的路径
//把上下文当中的状态应用到所有路径当中.
CGContextStrokePath(ctx);
}
- 第二种
图2
#import "DrawView.h"
@implementation DrawView
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef ctx = UIGraphicsGetCurrentContext();
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(20, 150)];
[path addLineToPoint:CGPointMake(280, 150)];
CGContextAddPath(ctx, path.CGPath);
//1.把当前上下文的状态保存到上下文状态栈
CGContextSaveGState(ctx);
CGContextSetLineWidth(ctx, 10);
[[UIColor redColor] set];
//2.把当前上下文的状态保存到上下文状态栈
CGContextSaveGState(ctx);
//取出上下文当中所有绘制的路径
//把上下文当中的状态应用到所有路径当中.
CGContextStrokePath(ctx);
UIBezierPath *path2 = [UIBezierPath bezierPath];
[path2 moveToPoint:CGPointMake(150, 20)];
[path2 addLineToPoint:CGPointMake(150, 280)];
CGContextAddPath(ctx, path2.CGPath);
//CGContextSetLineWidth(ctx, 1);
//[[UIColor blackColor] set];
//从上下文状态栈中取出状态
//从当前的上下文状态栈中取出栈顶的状态,覆盖掉当前的上下文状态
CGContextRestoreGState(ctx);
//取出上下文当中所有绘制的路径
//把上下文当中的状态应用到所有路径当中.
CGContextStrokePath(ctx);
}
@end
三、图形上下文的矩阵操作
#import "VcView.h"
@implementation VcView
- (void)drawRect:(CGRect)rect {
// Drawing code
//这个上下文的矩阵操作,坐标和view的坐标不一样,感觉有点怪怪的。
CGContextRef ctx = UIGraphicsGetCurrentContext();
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 200, 100)];
//形变操作
//CGContextTranslateCTM(ctx, 0, 100);
//CGContextScaleCTM(ctx, 1.5, 1.5);
CGContextRotateCTM(ctx, M_PI_4);
CGContextAddPath(ctx, path.CGPath);
[[UIColor redColor] set];
CGContextFillPath(ctx);
}
@end
四、生成图片
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//生成图片可以在任何想要的地方生成图片
//0.加载图片
UIImage *image = [UIImage imageNamed:@"阿狸头像"];
NSString *text = @"我是阿狸";
//加水印,生成图片
//1.手动开启一个位图上下文(创建位图上下文时,要指定大小,决定着生成图片的尺寸是多大)
UIGraphicsBeginImageContext(image.size);
//2.把内容绘制到上下文当中
[image drawAtPoint:CGPointZero];
[text drawAtPoint:CGPointMake(50, 150) withAttributes:@{
NSFontAttributeName:[UIFont systemFontOfSize:30]
}];
//3.从上下文当中生成一张图片(把上下文当中绘制的所有内容合成一张跟上下文大小一样的图片)
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
//手动创建的位图上下文,要销毁
UIGraphicsEndImageContext();
self.iamgeView.image = newImage;
}
五、图片裁剪
1.不带边框的裁剪
- (void)viewDidLoad {
[super viewDidLoad];
//1.加载图片
UIImage *image = [UIImage imageNamed:@"阿狸头像"];
//2.开启一个位图上下文
UIGraphicsBeginImageContext(image.size);
//3.设置一个圆形的裁剪区域
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
//把路径设置为裁剪区域(超出裁剪区域以外的内容会被自动裁剪掉)
[path addClip];//对后面绘制的内容有效果, 已经绘制到上下文当中的内容,不会被裁剪
//4.把图片绘制到上下文当中
[image drawAtPoint:CGPointZero];
//5.从上下文当中生成一张图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
//6.关闭上下文
UIGraphicsEndImageContext();
self.imageView.image = newImage;
}
2.带边框的裁剪
image.png
- (void)viewDidLoad {
[super viewDidLoad];
// //0.加载图片,设置边框的宽度
UIImage *image = [UIImage imageNamed:@"阿狸头像"];
CGFloat borderW = 10.0;
//1.先开启一个图片上下文 ,尺寸大小在原始图片基础上宽高都加上两倍边框宽度.
CGSize size = CGSizeMake(image.size.width + 2 * borderW, image.size.height + 2 * borderW);
UIGraphicsBeginImageContext(size);
//2.填充一个圆形路径.这个圆形路径大小,和上下文尺寸大小一样.
//把大圆画到上下文当中.
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, size.width, size.height)];
[[UIColor redColor] set];
[path fill];
//3.添加一个小圆,小圆,x,y从边框宽度位置开始添加,宽高和原始图片一样大小.把小圆设为裁剪区域.
UIBezierPath *clipPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(borderW, borderW, image.size.width, image.size.height)];
//把小圆设为裁剪区域.
[clipPath addClip];
//4.把图片给绘制上去.
[image drawAtPoint:CGPointMake(borderW, borderW)];
//5.从上下文当中生成一张图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
//6.关闭上下文
UIGraphicsEndImageContext();
}
六、截屏
1.截屏
image.png
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//生成一张图片
//1.开启位图上下文
UIGraphicsBeginImageContext(self.view.bounds.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
//2.把控制器View的内容绘制到上下文当中.(上下文与layer之间是通过渲染方式进行交互)
[self.view.layer renderInContext:ctx];
//3.从上下文当中生成一张图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
//文件是以二制流形式传输.
//NSData *data = UIImageJPEGRepresentation(newImage, 1.0);
NSData *data = UIImagePNGRepresentation(newImage);
[data writeToFile:@"/Users/apple/Desktop/newImage.png" atomically:YES];
//4.关闭上下文
UIGraphicsEndImageContext();
}
2.添加拖动遮罩
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (nonatomic, assign) CGPoint startP;
@property (nonatomic, weak) UIView *coverVeiw;
@end
@implementation ViewController
//1.什么时候使用,什么时候才去创建
//2.保证一个对象当前最多只创建一个
//3.保存该对象一直有值.
- (UIView *)coverVeiw {
if (_coverVeiw == nil) {
UIView *coverVeiw = [[UIView alloc] init];
coverVeiw.alpha = 0.7;
coverVeiw.backgroundColor = [UIColor blackColor];
[self.view addSubview:coverVeiw];
_coverVeiw = coverVeiw;
}
return _coverVeiw;
}
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)pan:(UIPanGestureRecognizer *)pan {
CGPoint curP = [pan locationInView:self.imageView];
//获取起始点
if (pan.state == UIGestureRecognizerStateBegan) {
//获取当前点
self.startP = curP;
}else if (pan.state == UIGestureRecognizerStateChanged) {
//获取当前点
CGFloat X = self.startP.x;
CGFloat Y = self.startP.y;
CGFloat W = curP.x - self.startP.x;
CGFloat H = curP.y - self.startP.y;
CGRect rect = CGRectMake(X, Y, W, H);
self.coverVeiw.frame = rect;
}else if(pan.state == UIGestureRecognizerStateEnded){
//开启一个位图上下文
UIGraphicsBeginImageContextWithOptions(self.imageView.bounds.size, NO, 0.0);
//UIRectClip(self.coverVeiw.frame);
UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.coverVeiw.frame];
[path addClip];
//把ImageView的内容渲染上下文当中.
CGContextRef ctx = UIGraphicsGetCurrentContext();
[self.imageView.layer renderInContext:ctx];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
self.imageView.image = newImage;
UIGraphicsEndImageContext();
[self.coverVeiw removeFromSuperview];
}
}
@end
3.图片擦除
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end
@implementation ViewController
- (void)viewDidLoad {
self.imageView.userInteractionEnabled = YES;
}
- (IBAction)pan:(UIPanGestureRecognizer *)pan {
//获取当前手指的点
UIImageView *imageV = (UIImageView *)pan.view;
CGPoint curP = [pan locationInView:imageV];
CGRect rect = CGRectMake(curP.x - 15, curP.y - 15, 30, 30);
//开启一个位图上下文
UIGraphicsBeginImageContextWithOptions(imageV.bounds.size, NO, 0.0);
//把ImageView内容渲染到上下文当中
CGContextRef ctx = UIGraphicsGetCurrentContext();
[imageV.layer renderInContext:ctx];
//擦除上下文当中某一块区域
CGContextClearRect(ctx, rect);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
imageV.image = newImage;
UIGraphicsEndImageContext();
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end













网友评论