美文网首页
02.4--iOSQuartz 2D

02.4--iOSQuartz 2D

作者: weyan | 来源:发表于2018-11-25 08:31 被阅读0次

一、- (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

相关文章

网友评论

      本文标题:02.4--iOSQuartz 2D

      本文链接:https://www.haomeiwen.com/subject/irgvtqtx.html