Quartz 2D绘图 (2)再遇


图片裁剪

直接裁剪图片

  • 裁剪思路:

    • 绘制一个已经裁剪好的圆形的图形上下文
    • 将图片绘制上去就可以了
  • 代码

// 1.获取图形上下文
CGContextRef cxtRef = UIGraphicsGetCurrentContext();

// 2.圆形路径对象
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 150) radius:50 startAngle:0 endAngle:M_PI * 2 clockwise:YES];

// 3.将路径对象添加到上下文
CGContextAddPath(cxtRef, path.CGPath);

// 3.2裁剪图形上下文,注意:必须是在添加完路径对象后,并且是渲染之前进行裁剪,否则没有意义。
CGContextClip(cxtRef);

// 4.渲染
CGContextDrawPath(cxtRef, kCGPathStroke);

// 5.绘制图片绘制图片需要在最后进行绘制
UIImage *image = [UIImage imageNamed:@"me"];
[image drawAtPoint:CGPointMake(100, 100)];

保存到相册和沙盒

> 相册

  • 保存到相册
// 添加图片到相册中.  可选的监听方法格式如下:
//  - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;
UIKIT_EXTERN void UIImageWriteToSavedPhotosAlbum(UIImage *image, __nullable id completionTarget, __nullable SEL completionSelector, void * __nullable contextInfo);
  • 保存裁剪的图片
// 保存裁剪的图片到相册
UIImageWriteToSavedPhotosAlbum(imgCliped, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
#pragma mark - 监听保存图片的成功与失败
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
    if (error) {
        NSLog(@"保存失败");
    } else {
        NSLog(@"保存成功");
    }
}

> 沙盒

  • 保存到沙盒

    • 获取文件路径
    • 将图片文件转为二进制数据
    • 将二进制数据写入到文件
  • 参考代码

// 保存到沙盒
// 文件路径
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"abc.png"];
NSLog(@"%@", filePath);
// 转为二进制文件
NSData *imgData = UIImagePNGRepresentation(imgCliped);
// 写入文件
[imgData writeToFile:filePath atomically:YES];

裁剪带圆环的图片

  • 裁剪思路:

    • 先绘制一个圆环
    • 再绘制要裁剪的图形
    • 最后在进行裁剪
  • 参考代码

    #pragma mark - 裁剪带圆环的图形
    // 加载图片显示
    UIImage *image = [UIImage imageNamed:@"me"];
    self.imgView.image = image;
    
    // 1.开启图片的图形上下文
    CGFloat margin = 10;
    CGSize size = CGSizeMake(image.size.width + 2 * margin, image.size.height + 2 * margin);
    UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
    
    // 2.获取当前的图形上下文
    CGContextRef cxtRef = UIGraphicsGetCurrentContext();
    
    // 圆心
    CGPoint center = CGPointMake(size.width * 0.5, size.height * 0.5);
    
    // 2.1绘制圆环
    // 半径 需要让圆环的半径刚好可以正其先换在最外面
    CGFloat radius = MIN(size.width, size.height) * 0.5 - margin * 0.5;
    // 圆环的路径
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    
    CGContextSetLineWidth(cxtRef, margin);
    [[UIColor redColor] set];
    
    // 2.1.2添加
    CGContextAddPath(cxtRef, path.CGPath);
    // 2.2.3将圆环部分渲染
    CGContextDrawPath(cxtRef, kCGPathFill);
    
    // 2.2绘制要裁剪的图形
    CGFloat radius2 = MIN(image.size.width, image.size.height) * 0.5;
    UIBezierPath *path2 = [UIBezierPath bezierPathWithArcCenter:center radius:radius2 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    // 2.2.2添加
    CGContextAddPath(cxtRef, path2.CGPath);
    
    // 5.裁剪
    CGContextClip(cxtRef);
    
    // 6.绘制图片
    [image drawAtPoint:CGPointMake(margin, margin)];
    
    // 7.从当前图形上下文中获取图片
    UIImage *imgClicped = UIGraphicsGetImageFromCurrentImageContext();
    
    UIGraphicsEndImageContext();
    
    self.imgView.image = imgClicped;
    

裁剪带圆环的图片

  • 裁剪思路:

    • 先绘制一个圆环
    • 再绘制要裁剪的图形
    • 最后在进行裁剪
  • 参考代码

    #pragma mark - 裁剪带圆环的图形
    // 加载图片显示
    UIImage *image = [UIImage imageNamed:@"me"];
    self.imgView.image = image;
    
    // 1.开启图片的图形上下文
    CGFloat margin = 10;
    CGSize size = CGSizeMake(image.size.width + 2 * margin, image.size.height + 2 * margin);
    UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
    
    // 2.获取当前的图形上下文
    CGContextRef cxtRef = UIGraphicsGetCurrentContext();
    
    // 圆心
    CGPoint center = CGPointMake(size.width * 0.5, size.height * 0.5);
    
    // 2.1绘制圆环
    // 半径 需要让圆环的半径刚好可以正其先换在最外面
    CGFloat radius = MIN(size.width, size.height) * 0.5 - margin * 0.5;
    // 圆环的路径
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    
    CGContextSetLineWidth(cxtRef, margin);
    [[UIColor redColor] set];
    
    // 2.1.2添加
    CGContextAddPath(cxtRef, path.CGPath);
    // 2.2.3将圆环部分渲染
    CGContextDrawPath(cxtRef, kCGPathFill);
    
    // 2.2绘制要裁剪的图形
    CGFloat radius2 = MIN(image.size.width, image.size.height) * 0.5;
    UIBezierPath *path2 = [UIBezierPath bezierPathWithArcCenter:center radius:radius2 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    // 2.2.2添加
    CGContextAddPath(cxtRef, path2.CGPath);
    
    // 5.裁剪
    CGContextClip(cxtRef);
    
    // 6.绘制图片
    [image drawAtPoint:CGPointMake(margin, margin)];
    
    // 7.从当前图形上下文中获取图片
    UIImage *imgClicped = UIGraphicsGetImageFromCurrentImageContext();
    
    UIGraphicsEndImageContext();
    
    self.imgView.image = imgClicped;
    

屏幕截图

  • 屏幕截图过程
    • 开启图片的图形上下文
    • 获取当前的图形上下文
    • 将view的layer渲染到图形上下文中
    • 从当前的图形上下文中获取图片
  • 参考代码
    // 1.开启图片的图形上下文
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0.0);
    
    // 2.获取当前的图形上下文
    CGContextRef cxtRef = UIGraphicsGetCurrentContext();
    
    // 3.将view的layer渲染到图形上下文中
    [self.view.layer renderInContext:cxtRef];
    
    // 4.从当前的图形上下文中获取图片
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    
    // 5.关闭图形上下文
    UIGraphicsEndImageContext();
    
    // 6.将图片保存到相册中
    UIImageWriteToSavedPhotosAlbum(img, nil, nil, nil);
    

触摸事件介绍

  • iOS中事件大体分为三类:触摸事件、加速计事件、远程控制事件
  • 需要掌握4中触摸事件
  • 不接受用户触摸事件的几种情况
  • 了解响应者链条
  • 手势识别

4种触摸事件

  • 什么类型的对象是响应者对象呢?

    • 只要这个对象的类型是直接或者间接的继承自UIResponder,那么这个对象就是响应者对象。
  • 4种触摸事件

    #pragma mark - 当手指按下的时候调用
    - (void)touchesBegan:(NSSet *)touches withEvent:(nullable UIEvent *)event;
    #pragma mark - 当手指移动的时候调用
    - (void)touchesMoved:(NSSet *)touches withEvent:(nullable UIEvent *)event;
    #pragma mark - 当手指抬起的时候调用
    - (void)touchesEnded:(NSSet *)touches withEvent:(nullable UIEvent *)event;
    #pragma mark - 当有一些系统事件的时候调用,会打断对手指的跟踪行为
    - (void)touchesCancelled:(nullable NSSet *)touches withEvent:(nullable UIEvent *)event;
    
  • touches参数是NSSet类型

    • 特点是:1.无序 2.集合内的元素不重复
    • 遍历:可以通过forIn遍历
    • 取值:通过anyObject来获取对应的值
    • 在当前集合参数中装的都是UITouch类型的触摸对象
  • event参数是UIEvent类型

    • 用来区分是那种情况的触摸事件
    • 可以根据类型type和子类型subtype来确定是那种触摸事件。

触摸事件的响应顺序和不接受触摸事件的几种情况

  • 触摸事件的响应顺序

    • 首先是最顶层的view被触发[第一响应者]
    • 然后是向下传,所有嵌套的view依次被触发
    • 控制器的view里面也是会被触发的。
  • 不接受触摸事件的几种情况

    • 1> 控件的hidden为YES的时候,不会触发
    • 2> 控件的User Interaction Enable 取消,不会触发
    • 3> 控件的父控件不能进行用户交互的时候,不会触发
    • 4> 控件的透明度小于等于0.01的时候,不会触发
    • 5> 控件不在父控件的有效范围内的时候,不会触发
    • 6> 图片框默认是不能接受用户交互的
    • 6> 对于按钮来说,按钮接收到用户事件后,会将用户响应事件切断,所以它的父控件就不会再去响应事件了。

触摸事件的产生和传递过程

  • 触摸事件的产生

    • 当用户点击屏幕的时候就会产生UITouch类型的触摸对象,进而产生一系列的触摸事件
  • 触摸事件的传递过程

    • 1> 应用程序启动完毕后,内部就有一个运行循环,始终监听用户的触摸事件及其他的事件

    • 2> 首先,iOS监听到触摸点后,会把这个消息交给UIApplication对象,说"现在又触摸对象了,看一下按的是谁",

    • 3> UIApplication就直接告诉UIWindow"现在有用户触摸点了,看一下点的谁",

    • 4> 然后UIWindow就告诉控制器,现在有用户手指触摸屏幕,看一下是按到谁了,如果有导航控制器的及根控制器的话,会继续往下传递这个事件,传给最终在显示的控制器

    • 5> 最终显示的控制器拿到事件再传给它的view,控制器的view再搜索他自己的子控件,从后往前问,找到对应被点击的view。

    • 6> 找到被点击的view后,将消息一次返回说明找到了对应的view,应用程序再找对应view的注册事件,然后就执行对应的事件。前提是得基于触摸事件。

    • 7> 从用户触摸事件产生,然后从上往下传递事件。

    • 事件传递过程中涉及的方法有:

      • hitTest:当事件从上往下传的时候,递归查找那个view被点了。内部算法的原因会重复调用了两次

      • 控制器也是知道这个事件的,事件时通过控制器传递过来的

      • pointInside:WithEvent方法,确定事件到底在不在view内部。

      • hitTest就是用来测试控件是否可以响应事件。

手势识别介绍

  • 在以前如果想监听一个view上的触摸事件,之前的做法是

    • 自定义一个view

    • 实现view的touches方法,在方法内部实现具体处理代码

    • 通过touches方法监听view的触摸事件,有很明显的几个缺点

      • 必须得自定义view
      • 由于是在view内部的touches方法中监听触摸事件,因此默认情况下,无法让其他外界对象监听view的触摸事件。
      • 不容易具体区分用户的具体手势行为
  • 在iOS3.2 之后,苹果退出了手势识别功能(Gesture Recognizer),在触摸事件处理方面,大大简化了开发者的开发难度。

  • 6种常用的手势识别器

    • UITapGestureRecognizer :轻按手势

    • UIPinchGestureRecognizer :缩放手势

    • UIRotationGestureRecognizer :旋转手势

    • UISwipeGestureRecognizer :清扫手势

    • UIPanGestureRecognizer :拖拽手势

    • UILongPressGestureRecognizer :长按手势

  • 手势识别的使用方法。
    实例化,指定监听方法
    添加到view上
    实现对应的方法。

注意:imageView默认不支持多手势操作和用户交互,但是从媒体库拖入的图片是支持用户交互和多手势的。

你可能感兴趣的:(Quartz 2D绘图 (2)再遇)