Quartz2D

作者: 小的小碰撞 | 来源:发表于2019-04-15 10:03 被阅读0次
    • Quartz2D 是一个二维绘图引擎
    图形上下文
    • 图形上下文(Graphics Context): 是一个CGContextRef类型的数据
    • 作用:
      • 保存绘图信息绘图状态
      • 决定绘制的输出目标(绘制到什么地方去?)


        image.png
    Quartz2D 绘图的代码步骤
    • 1.获得图形上下文CGContextRef ctx = UIGraphicsGetCurrentContext();

    • 2.拼接路径

    CGContextMoveToPoint(ctx,10,10);
    CGContextAddLineToPoint(ctx,100,100);
    
    • 3.绘制路径
    CGContextStrokePath(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,CGRext rect)

    • 添加一个圆弧 void CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)

    • Mode参数决定绘制的模式void CGContextDrawPath(CGContextRef c,CGPathDrawinMode mode)

    • 绘制空心路径void CGContextStrokePath(CGContextRef c)

    • 绘制实心路径void CGContextFillPah(CGContextRef c)

    图形上下文栈的操作
    • 将当前的上下文copy一份,保存到栈顶void CGContextSaveGState(CGContextRef c)
    • 将栈顶的上下文出栈,替换掉当前的上下文void CGContextRestoreGState(CGContextRef c)
    矩阵操作
    • 利用矩阵操作,能让绘制到上下文中的所有路径一起发生变化

      • 缩放void CGContextScaleCTM(CGContextRef c,CGFloat sx ,CGFloat sy)
      • 旋转void CGContextRotateCTM(CGContextRef c,CGFloat angle)
      • 平移void CGContextTranslateCTM(CGContextRef c,CGFloat tx ,CGFloat ty)
    • 自定义view的基本步骤

      • 获取图形上下文
      • 创建(描绘)路径
      • 把路径添加到上下文
      • 渲染上下文
     - (Void) drawRect:(CGRect)rect {
     // 1.获取图形上下文
        // 目前我们所用的上下文都是以UIGraphics
        // CGContextRef Ref:引用 CG:目前使用到的类型和函数 一般都是CG开头 CoreGraphics
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        // 2.描述路径
        // 创建路径
        CGMutablePathRef path = CGPathCreateMutable();
        // 设置起点
        // path:给哪个路径设置起点
        CGPathMoveToPoint(path, NULL, 50, 50);
        // 添加一根线到某个点
        CGPathAddLineToPoint(path, NULL, 200, 200);
        // 3.把路径添加到上下文
        CGContextAddPath(ctx, path);
        // 4.渲染上下文
        CGContextStrokePath(ctx);
    }
    - (void)drawRect:(CGRect)rect {
     UIBezierPath *path = [UIBezierPath bezierPath];
        
        // 设置起点
        [path moveToPoint:CGPointMake(50, 50)];
        
        // 添加一根线到某个点
        [path addLineToPoint:CGPointMake(200, 200)];
        
        // 绘制路径
        [path stroke];
    }
    
    
    • 为什么要实现drawRect:方法才能绘图到view上?
      • 因为在drawRect:方法中才能获取到跟view相关联的图形上下文
    • drawRect:方法什么时候调用?
    • 当view第一次显示到屏幕上的时(被加到UIWindow上显示出来)
    • 调用view的setNeedsDisplay或者setNeedsDisplayInrect时
    绘制图片和文字
    • drawInRect:withAttributesdrawAtPoint:withAttributes 的区别
    • drawInRect:withAttributes可以换行
    NSString *str = @"An empty implementation adversely affects performance during animation.";
       
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        dict[NSForegroundColorAttributeName] = [UIColor redColor];
        
        dict[NSFontAttributeName] = [UIFont systemFontOfSize:19];
        
        // 不会换行
        [str drawAtPoint:CGPointZero withAttributes:nil];
        // 可以换行
        [str drawInRect:rect withAttributes:dict];
    
    • drawAtPoint:默认绘制的内容和图片的尺寸大小一样
    • drawInRect
    • drawAsPatternInRect 绘制图片 平铺
    定时器
    • NSTimer很少用于绘图,因为调度优先级比较低,并不会准时调用,通常使用CADisplayLink
    • setNeedsDisplay 这个方法并不会马上调用drawRect,其实这个方法只是给当前控件添加刷新的标记,等下一次屏幕刷新的时候才会调用drawRect
    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(timeChange)];
        // 添加主运行循环
        [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    
    • 矩阵方法
    - (void)drawRect:(CGRect)rect {
        
        // 1.获取上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        // 2.描述路径
       UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-100, -50, 200, 100)];
        [[UIColor redColor] set];
        // 上下文矩阵操作
        // 注意:矩阵操作必须要在添加路径之前
        //  平移
        CGContextTranslateCTM(ctx, 100, 50);
        // 缩放
        CGContextScaleCTM(ctx, 0.5, 0.5);
        // 旋转
        CGContextRotateCTM(ctx, M_PI_4);
        
        // 3.把路径添加上下文
        CGContextAddPath(ctx, path.CGPath);
        [[UIColor redColor] set];
        // 4.渲染上下文
        CGContextFillPath(ctx);
    
    }
    
    图片水印
    • 开启一个基于位图的图形上下文void UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque ,CGFloat scale)
      • size: 大小
      • opaque: 不透明度 (NO为透明,一般弄透明的上下文 )
      • scale: 缩放,通常不需要缩放上下文,取值为0 ,表示不缩放
    • 从上下文中获取图片UIImage * UIGraphicsGetImageFromCurrentImageContext()
    • 结束基于位图的图形上下文void UIGraphicsEndImageContext()
    - (Void)waterImage {
    // 加载图片
        UIImage *image = [UIImage imageNamed:@"nihao"];
        // 0.获取上下文,之前的上下文都是在view的drawRect方法中获取(跟View相关联的上下文layer上下文)
        // 目前我们需要绘制图片到新的图片上,因此需要用到位图上下文
        // 怎么获取位图上下文,注意位图上下文的获取方式跟layer上下文不一样。位图上下文需要我们手动创建。
        // 开启一个位图上下文,注意位图上下文跟view无关联,所以不需要在drawRect.
        // size:位图上下文的尺寸(新图片的尺寸)
        // opaque: 不透明度 YES:不透明 NO:透明,通常我们一般都弄透明的上下文
        // scale:通常不需要缩放上下文,取值为0,表示不缩放
        UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
        // 1.绘制原生的图片
        [image drawAtPoint:CGPointZero];
        // 2.给原生的图片添加文字
        NSString *str = @"我是水印";
        [str drawAtPoint:CGPointMake(200, 528) withAttributes:nil];
        // 3.生成一张图片给我们,从上下文中获取图片
        UIImage *imageWater = UIGraphicsGetImageFromCurrentImageContext();
        // 4.关闭上下文
        UIGraphicsEndImageContext();
        _imageView.image = imageWater;
    }
    
    图片剪裁
    • 将当前上下文所绘制的路径都剪裁出来(超出这个剪裁区域的都不能显示)void CGContextClip(CGContextRef c)
    • 步骤
      • 开启位图上下文
      • 设置原型裁剪区域
      • 绘制图片
      • 从上下文中获取图片
      • 关闭上下文
    - (void)clipImage
    {
        // 0.加载图片
        UIImage *image = [UIImage imageNamed:@"阿狸头像"];
        
        // 1.开启位图上下文,跟图片尺寸一样大
        UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
        
        // 2.设置圆形裁剪区域,正切与图片
        // 2.1创建圆形的路径
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
        
        // 2.2把路径设置为裁剪区域
        [path addClip];
        
        // 3.绘制图片
        [image drawAtPoint:CGPointZero];
        
        // 4.从上下文中获取图片
        UIImage *clipImage = UIGraphicsGetImageFromCurrentImageContext();
        
        // 5.关闭上下文
        UIGraphicsEndImageContext();
        
        _imageView.image = clipImage;
    }
    
    屏幕截图
    • 图片转化成NSData UIImageJPEGRepresentation
    • 将图片保存到指定文件[data writeToFile:@"/Users/xxx//Desktop/close.png" atomically:YES]
    + (UIImage *)imageWithCaputureView:(UIView *)view
    {
        // 开启位图上下文
        UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 0);
        
        // 获取上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        
        // 把控件上的图层渲染到上下文,layer只能渲染
        [view.layer renderInContext:ctx];
        
        // 生成一张图片
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        
        // 关闭上下文
        UIGraphicsEndImageContext();
        
        return image;
    }
    
    图片截屏
    • pan 手势拖拽
    - (void)setuiPan {
    // 给控制器的view添加一个pan手势  拖拽
        UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
        [self.view addGestureRecognizer:pan];
    }
    
    - (void)pan:(UIPanGestureRecognizer *)pan {
        // 获取偏移量
        // 返回的是相对于最原始的手指的偏移量
        CGPoint transP = [pan translationInView:self.imageV];
        // 移动图控件
        self.imageV.transform = CGAffineTransformTranslate(self.imageV.transform, transP.x, transP.y);
        // 复位
        [pan setTranslation:CGPointZero inView:self.view];
        
    }
    
    
    • 屏幕截图
      • 在一个背景image上移动半透明的view,形成截屏的view
    - (void)setupPan {
      UIPanGestureRecongnizer *pan = [UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
    }
    
    - (void)pan:(UIPanGestureRecognizer *)pan
    {
        CGPoint endA = CGPointZero;
        
        if (pan.state == UIGestureRecognizerStateBegan) { // 一开始拖动的时候
            
            // 获取一开始触摸点
          _startP = [pan locationInView:self.view];
            
        }else if(pan.state == UIGestureRecognizerStateChanged){ // 一直拖动
            // 获取结束点
             endA = [pan locationInView:self.view];
            
            CGFloat w = endA.x - _startP.x;
            CGFloat h = endA.y - _startP.y;
            
            // 获取截取范围
            CGRect clipRect = CGRectMake(_startP.x, _startP.y, w, h);
    
            // 生成截屏的view
            self.clipView.frame = clipRect;
            
        }else if (pan.state == UIGestureRecognizerStateEnded){
            
            // 图片裁剪,生成一张新的图片
            // 开启上下文
            // 如果不透明,默认超出裁剪区域会变成黑色,通常都是透明
            UIGraphicsBeginImageContextWithOptions(_imageV.bounds.size, NO, 0);
            
            // 设置裁剪区域
           UIBezierPath *path =  [UIBezierPath bezierPathWithRect:_clipView.frame];
            
            [path addClip];
            
            // 获取上下文
            CGContextRef ctx = UIGraphicsGetCurrentContext();
            
            // 把控件上的内容渲染到上下文
            [_imageV.layer renderInContext:ctx];
            
            
            // 生成一张新的图片
            _imageV.image = UIGraphicsGetImageFromCurrentImageContext();
            
            
            // 关闭上下文
            UIGraphicsEndImageContext();
            
            
            // 先移除
            [_clipView removeFromSuperview];
            // 截取的view设置为nil
            _clipView = nil;
            
        }
        // 获取手指的偏移量
    //    pan translationInView:<#(UIView *)#>
    }
    

    相关文章

      网友评论

          本文标题:Quartz2D

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