quartz 2d

作者: 目前运行时 | 来源:发表于2018-02-05 15:02 被阅读123次

    quartz 2d的知识我总是容易忘记,在这里打算花点时间整理一下,对自己和对大家都是有好处的,如果我有什么不对或者不全的地方 请大家给予指正,鄙人不胜感激。

    画一条直线

    绘图的基本步骤
    • 创建上下文(这个必须在drawRect方法才可以 ,默认view 调用一次,每次调用setNeedsDisplay 它会调用一次)
    • 对- (void)drawRect:(CGRect)rect说明
      1.调用时机:是在view加载完毕的时候开始调用
      2.rect 就是view的bounds
      3.用来专门绘制上下文的
    • 上下文步骤的详细说明
      1.创建上下文
      2.创建路径
      3.将路径添加到上下文
      4.开始绘制
    • 画一条直线的详细代码
    - (void)drawRect:(CGRect)rect {
        // 获取上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        // 创建路径
        UIBezierPath *path = [[UIBezierPath alloc] init];
        // 创建起点
        [path moveToPoint:CGPointMake(10, 100)];
        // 创建终点
        [path addLineToPoint:CGPointMake(100, 10)];
        // 在加上一个终点
        [path addLineToPoint:CGPointMake(180, 100)];
        // 设置线宽
        CGContextSetLineWidth(ctx, 10);
        // 设置颜色
        [[UIColor greenColor] setStroke];
        // 添加圆角(在两条线连接的地方)
        CGContextSetLineJoin(ctx, kCGLineJoinRound);
        // 设置两条线的尾部的圆角
        CGContextSetLineCap(ctx, kCGLineCapRound);
        // 将路径添加到上下文上
        CGContextAddPath(ctx, path.CGPath);
        // 进行绘制
        CGContextStrokePath(ctx);
    }
    
    1.png
    • 画一条曲线
    - (void)drawRect:(CGRect)rect {
        // 获取上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        // 创建路径
        UIBezierPath *path = [[UIBezierPath alloc] init];
        //创建起始点
        [path moveToPoint:CGPointMake(10, 100)];
        // 画曲线
        [path addQuadCurveToPoint:CGPointMake(180, 100) controlPoint:CGPointMake(100, 0)];
        // 设置颜色
        [[UIColor greenColor] setStroke];
        // 设置线宽
        CGContextSetLineWidth(ctx, 10);
        // 设置两条线的尾部的圆角
        CGContextSetLineCap(ctx, kCGLineCapRound);
        // 将路径添加到上下文上
        CGContextAddPath(ctx, path.CGPath);
        // 进行绘制
        CGContextStrokePath(ctx);
    }
    
    2.png
    • 画一个长方形或者正方形
    - (void)drawRect:(CGRect)rect {
        // 用这个方法创建的时候已经默认创建了上下文
        UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(10, 10, 100, 100)];
        // 设置四个角的样式
        path.lineJoinStyle = kCGLineJoinRound;
        // 设置颜色
        [[UIColor greenColor] setStroke];
        // 设置边角宽度
        path.lineWidth = 10.0;
        // 开始绘制
        [path stroke];
    }
    
    2.png
    • 画一个圆形
    - (void)drawRect:(CGRect)rect {
        
        // 用这个方法创建的时候已经默认创建了上下文
        UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(10, 10, 100, 100) cornerRadius:50];
        // 设置四个角的样式
        path.lineJoinStyle = kCGLineJoinRound;
        // 设置颜色
        [[UIColor greenColor] setStroke];
        // 设置边角宽度
        path.lineWidth = 10.0;
        // 开始绘制
        [path stroke];
    
    } 
    
    1.png
    • 画一个实心圆 用另外的一种方法
    - (void)drawRect:(CGRect)rect {
       
        // 创建上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        // frame
        CGRect frame = CGRectMake(10, 10, 100, 100);
        // 设置颜色
        [[UIColor greenColor] set];
        // 画一个圆形的区域
        CGContextAddEllipseInRect(ctx, frame);
        // 开始绘制
        CGContextFillPath(ctx);
    
    } 
    
    1.png
    • 画一个椭圆(空心的)
    - (void)drawRect:(CGRect)rect {
        // 创建路径
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 180, 100)];
        // 设置宽度
        path.lineWidth = 10;
        // 设置颜色
        [[UIColor greenColor] setStroke];
        // 开始绘制
        [path stroke];
    }
    
    空心的椭圆.png
    • 画一个实心的椭圆
    /**
     画一个实心的椭圆
     */
    - (void)drawRealOval {
        // 创建路径
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 180, 100)];
        // 设置颜色
        [[UIColor greenColor] setFill];
        // 开始绘制
        [path fill];
    }
    
    实心的椭圆.png
    • 画一个空心的圆弧
    /**
     画一个空心的圆弧
     */
    -(void)drawArc {
        // 开始的角度
        CGFloat startA = -M_PI_2;
        // 结束的角度
        CGFloat endA = M_PI_2;
        // 开始创建路径(clockwise : yes  是顺时针 no:逆时针)
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 100) radius:80 startAngle:startA endAngle:endA clockwise:YES];
        // 设置颜色
        [[UIColor greenColor] setStroke];
        // 宽度
        path.lineWidth = 10;
        // 开始绘制
        [path stroke];
    }
    
    空心的圆弧.png
    • 画一个实心的圆弧
    /**
     画一个实心的圆弧
     */
    - (void)drawRealArc {
        // 开始的角度
        CGFloat startA = -M_PI_2;
        // 结束的角度
        CGFloat endA = M_PI_2;
        // 开始创建路径(clockwise : yes  是顺时针 no:逆时针)
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 100) radius:80 startAngle:startA endAngle:endA clockwise:YES];
        // 设置颜色
        [[UIColor greenColor] setFill];
        // 开始绘制
        [path fill];
    }
    
    实心圆弧.png
    • 画一个字符串( [str drawAtPoint:CGPointZero withAttributes:dic];其中它与 [str drawInRect:rect withAttributes:dic]的区别是drawInRect:rect可以换行的)
    - (void)drawRect:(CGRect)rect {
        NSString *str = @"哈哈哈哈";
        NSShadow *shadow = [[NSShadow alloc] init];
        // 宽高的偏移
        shadow.shadowOffset = CGSizeMake(10, 10);
        // 暗影颜色
        shadow.shadowColor = [UIColor greenColor];
        // 模糊
        shadow.shadowBlurRadius = 5;
        NSDictionary *dic = @{
                              NSFontAttributeName:[UIFont systemFontOfSize:30],
                              NSForegroundColorAttributeName : [UIColor whiteColor],
                              NSShadowAttributeName : shadow
                              };
        [str drawAtPoint:CGPointZero withAttributes:dic];
       
    }
    
    1.png
    • 画文字 2( [str drawInRect:rect withAttributes:dic];)
    - (void)drawRect:(CGRect)rect {
        
        NSString *str = @"哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈";
        NSShadow *shadow = [[NSShadow alloc] init];
        // 宽高的偏移
        shadow.shadowOffset = CGSizeMake(10, 10);
        // 暗影颜色
        shadow.shadowColor = [UIColor greenColor];
        // 模糊
        shadow.shadowBlurRadius = 5;
        NSDictionary *dic = @{
                              NSFontAttributeName:[UIFont systemFontOfSize:30],
                              NSForegroundColorAttributeName : [UIColor whiteColor],
                              NSShadowAttributeName : shadow
                              };
        [str drawInRect:rect withAttributes:dic];
    }
    
    2.png
    • image的绘制
    - (void)drawRect:(CGRect)rect {
       
        UIImage *image = [UIImage imageNamed:@"1"];
        // 这个可以把一整张图片显示完全
        [image drawInRect:rect];
    }
    
    2.png
    • image的另外一个显示方法
    - (void)drawRect:(CGRect)rect {
        UIImage *image = [UIImage imageNamed:@"1"];
        // 显示不完全 按照实际的比例进行显示
        [image drawAtPoint:CGPointZero];
    }
    
    3.png
    • image 平铺的方式
    - (void)drawRect:(CGRect)rect {
        UIImage *image = [UIImage imageNamed:@"美眉"];
        // 显示不完全 按照实际的比例进行显示
        [image drawAsPatternInRect:rect];
    }
    
    4.png
    • 接下来模仿一下系统的imageview的方法,具体代码我会写详细的注释,为了自己以后忘记的时候能够回来看看
      1)写一个自定义的view(LDGImageView.h 文件)
    #import <UIKit/UIKit.h>
    
    @interface LDGImageView : UIView
    
    /** image*/
    @property (nonatomic, strong) UIImage *image;
    /**
     初始化
    
     @param image image
     @return 对象本身
     */
    - (instancetype)initWithImage:(UIImage *)image;
    
    @end
    

    2)LDGImageView.m 文件

    #import "LDGImageView.h"
    
    @implementation LDGImageView
    
    -(void)setImage:(UIImage *)image {
        _image = image;
        [self setNeedsDisplay];
    }
    /**
     初始化
     
     @param image image
     @return 对象本身
     */
    - (instancetype)initWithImage:(UIImage *)image {
        if (self = [super init]) {
            self.image = image;
            self.frame = CGRectMake(0, 0, image.size.width, image.size.height);
            [self setNeedsDisplay];
        }
        return self;
        
    }
    - (void)drawRect:(CGRect)rect {
        [self.image drawInRect:rect];
        
    }
    

    3)viewController的使用
    3.1)普通方法的调用

     LDGImageView *imageView = [[LDGImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
        imageView.image = [UIImage imageNamed:@"1"];
        [self.view addSubview:imageView];
    
    7.png

    3.2) initimage方法的调用

     LDGImageView *imageView = [[LDGImageView alloc] initWithImage:[UIImage imageNamed:@"1"]];
        [self.view addSubview:imageView];
    
    5.png

    3.3) 切换image也是可以的,这里不做演示了。

    • 图形上下文的状态栈
    - (void)drawRect:(CGRect)rect {
        //  创建上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        //  创建路径
        UIBezierPath *path = [UIBezierPath bezierPath];
        //  创建一条直线
        [path moveToPoint:CGPointMake(10, 100)];
        [path addLineToPoint:CGPointMake(190, 100)];
        //  将当前的上下文添加到上下文的栈里
        CGContextSaveGState(ctx);
        //  设置颜色和宽度
        [[UIColor greenColor] setStroke];
        CGContextSetLineWidth(ctx, 10);
        //  将路径添加到上下文上
        CGContextAddPath(ctx, path.CGPath);
        //  开始绘制
        CGContextStrokePath(ctx);
        
        // 从新初始化路径
        path = [UIBezierPath bezierPath];
        // 恢复最开始的状态
        CGContextRestoreGState(ctx);
        // 绘制路径
        [path moveToPoint:CGPointMake(100, 10)];
        [path addLineToPoint:CGPointMake(100, 190)];
        //  设置颜色和宽度
        [[UIColor blueColor] setStroke];
        CGContextSetLineWidth(ctx, 5);
        // 将路径添加到上下文上
        CGContextAddPath(ctx, path.CGPath);
        // 开始绘制
        CGContextStrokePath(ctx);
    }
    
    1.png
    • 图形上下文的矩阵操作
      1.1) 平移
    - (void)drawRect:(CGRect)rect {
        // 创建上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        // 创建一个实心圆
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 50, 50)];
        // 设置颜色
        [[UIColor greenColor] setFill];
        // 平移
        CGContextTranslateCTM(ctx, 100, 120);
        // 开始绘制
        [path fill];
    }
    
    1.png

    1.2)旋转

    - (void)drawRect:(CGRect)rect {
        
        // 创建上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        // 创建一个实心圆
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 100, 50)];
        // 设置颜色
        [[UIColor greenColor] setFill];
        // 旋转
        CGContextRotateCTM(ctx, M_PI_4);
        // 开始绘制
        [path fill];
     
    }
    
    2.png

    1.3)缩放大小

    - (void)drawRect:(CGRect)rect {
        
        // 创建上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        // 创建一个实心圆
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 100, 50)];
        // 设置颜色
        [[UIColor greenColor] setFill];
        // 缩放
        CGContextScaleCTM(ctx, 2.0, 2.0);
        // 开始绘制
        [path fill];
    }
    
    3.png
    • 一个图片水印的例子,不用在drawrect方法里边实现了
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // 开启图片上下文
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 0.0);
        // 创建image
        UIImage *image = [UIImage imageNamed:@"美眉"];
        [image drawInRect:CGRectMake(0, 0, 200, 200)];
        // 创建logo文字
        NSString *str = @"阿斯顿哈说的";
        [str drawAtPoint:CGPointMake(20, 20) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0],
                                                              NSForegroundColorAttributeName :[UIColor redColor]
                                                              }];
        // 获得上下文生成的图片
        UIImage *getImage = UIGraphicsGetImageFromCurrentImageContext();
        // 结束当前图片上下文
        UIGraphicsEndImageContext();
        
        self.displayImageView.image = getImage;
    
    }
    
    4.png
    • 一个带有边框的圆形片的裁剪(给image加的分类)
    /**
     裁剪一个图片为圆形
     
     @param borderWidth 边框宽度
     @param borderColor 边框颜色
     @param imageViewWidth 外面的imageview的宽度,如果为0 将按照比例显示不按照正确的显示,如果imageview不是正方形请按照最小的传递
     @param imageName 图片的名字
     @return 想要的图片
     */
    +(UIImage *)imageWithBorderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor imageViewWidth:(CGFloat)imageViewWidth imageName:(NSString *)imageName {
        
        if (imageName.length == 0) {
            return nil;
        }
        UIImage *image = [UIImage imageNamed:imageName];
        CGFloat imageWidth = image.size.width;
        CGFloat imageHeight = image.size.height;
        imageWidth < imageHeight ? (imageHeight = imageWidth) : (imageWidth = imageHeight);
        // 这里为了精确显示传入进来的borderwidth,计算比例
        if (imageViewWidth > 0) {
            CGFloat scale = 1.0 * (imageWidth + 2*borderWidth)/imageViewWidth;
            if (scale < 1.0) {
                scale = 1.0 * imageWidth/imageViewWidth;
            }
            borderWidth = scale * borderWidth;
        }
        // 创建图片上下文
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(imageWidth + 2*borderWidth, imageHeight + 2*borderWidth), NO, 0.0);
        // 创建外面的大圆
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, imageWidth + 2*borderWidth, imageHeight + 2*borderWidth)];
        // 绘制颜色
        [borderColor set];
        // 填写
        [path fill];
        // 创建小圆
        CGRect rect = CGRectMake(borderWidth, borderWidth, imageWidth, imageHeight);
        path = [UIBezierPath bezierPathWithOvalInRect:rect];
        // 添加裁剪
        [path addClip];
        // 图片绘制
        [image drawInRect:rect];
        // 获取新的图片
        UIImage *getImage = UIGraphicsGetImageFromCurrentImageContext();
        // 关闭图片上下文
        UIGraphicsEndImageContext();
        return getImage;
    }
    
    图片本身大于imageview.png 图片本身小于imageview.png
    • 截屏
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        // 开启图片上下文
        UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0.0);
        // 获取上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        // 进行绘制
        [self.view.layer renderInContext:ctx];
        // 获取图片
        UIImage *getImage = UIGraphicsGetImageFromCurrentImageContext();
        // 关闭上下文
        UIGraphicsEndImageContext();
        // 保持原比例
        NSData *data = UIImageJPEGRepresentation(getImage, 1.0);
        [data writeToFile:@"/Users/apple/Desktop/l.jpg" atomically:YES];
    }
    
    1.png
    • 图片截屏
    /**
     拖拽事件
    
     @param sender 首饰
     */
    - (IBAction)panGesture:(UIPanGestureRecognizer *)sender {
        if (sender.state == UIGestureRecognizerStateBegan) {
            self.startP = [sender locationInView:self.view];
            
        }else if (sender.state == UIGestureRecognizerStateChanged){
            CGPoint currentP = [sender locationInView:self.view];
            CGFloat width = currentP.x - self.startP.x;
            CGFloat height = currentP.y - self.startP.y;
            self.corverView.frame = CGRectMake(self.startP.x, self.startP.y, width, height);
        }else if (sender.state == UIGestureRecognizerStateEnded){
            // 开启图片的上下文
            UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0.0);
            // 创建路径
            UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.corverView.frame];
            // 超出部分进行裁剪
            [path addClip];
            // 拿到当前的上下文
            CGContextRef ctx = UIGraphicsGetCurrentContext();
            // 开始绘制
            [self.displayImageView.layer renderInContext:ctx];
            // 获得图片
            UIImage *getImage = UIGraphicsGetImageFromCurrentImageContext();
            // 关闭上下文
            UIGraphicsEndImageContext();
            self.displayImageView.image = getImage;
            // 移除覆盖的view
            [self.corverView removeFromSuperview];
        }
    }
    
    1.png 2.png
    • 图片擦除
    - (IBAction)panGesture:(UIPanGestureRecognizer *)sender {
        
        // 擦除的宽度
        CGFloat width = 50;
        CGPoint currrentP = [sender locationInView:self.view];
        CGFloat pointX = currrentP.x - width *0.5;
        CGFloat pointY = currrentP.y - width *0.5;
        // 创建图片上下文
        UIGraphicsBeginImageContextWithOptions(self.displayImageView.bounds.size, NO, 0.0);
        // 获取当前的上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        // 进行绘制
        [self.displayImageView.layer renderInContext:ctx];
        // 擦除区域
        CGRect clearRect = CGRectMake(pointX, pointY, width, width);
        // 进行擦除
        CGContextClearRect(ctx, clearRect);
        // 生成新的图片
        UIImage *getImage = UIGraphicsGetImageFromCurrentImageContext();
        // 结束图片的上下文
        UIGraphicsEndImageContext();
        self.displayImageView.image = getImage;
    
    1.png
    • 一个手势解锁的例子(写的一般有时间在优化)
    #import "GestureView.h"
    #define ButtonW 70
    #define ButtonLeftMargen 30
    #define ButtonTopMargen 30
    #define ButtonCommonMargen 10
    
    @interface GestureView ()
    
    @property (strong, nonatomic) NSMutableArray *buttonArray;
    @property (assign, nonatomic) CGPoint currentP;
    
    @end
    @implementation GestureView
    
    -(NSMutableArray *)buttonArray {
        if (!_buttonArray) {
            _buttonArray = [NSMutableArray array];
        }
        return _buttonArray;
    }
    - (void)awakeFromNib {
        [super awakeFromNib];
        // 创建button
        for (NSInteger index = 0; index < 9; index ++) {
            UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
            [button setImage:[UIImage imageNamed:@"gesture_normal"] forState:UIControlStateNormal];
            [button setImage:[UIImage imageNamed:@"gesture_selected"] forState:UIControlStateSelected];
            button.tag = index;
            button.userInteractionEnabled = NO;
            [self addSubview:button];
        }
    }
    /**
     改变一些frame
     */
    - (void)layoutSubviews {
        [super layoutSubviews];
        // 在这里正式的设置button
        for (NSInteger index = 0; index < self.subviews.count; index++) {
            UIButton *button = (UIButton *)self.subviews[index];
            CGFloat buttonL = (index % 3)*(ButtonW + ButtonCommonMargen);
            CGFloat buttonT = (index / 3)*(ButtonW + ButtonCommonMargen);
            button.frame = CGRectMake(ButtonLeftMargen + buttonL, ButtonTopMargen + buttonT, ButtonW, ButtonW);
        }
    }
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        CGPoint currentP = [self getPointWithTouchs:touches];
        UIButton *button = [self getButtonThroughPoint:currentP];
        if (button && button.selected == NO) {
            button.selected = YES;
            [self.buttonArray addObject:button];
            [self setNeedsDisplay];
        }
    }
    -(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        CGPoint currentP = [self getPointWithTouchs:touches];
        UIButton *button = [self getButtonThroughPoint:currentP];
        if (button && button.selected == NO) {
            button.selected = YES;
            [self.buttonArray addObject:button];
            
        }
        self.currentP = currentP;
        [self setNeedsDisplay];
    }
    -(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        
        NSString *str = [[NSString alloc] init];
        for (UIButton *button in self.buttonArray) {
            button.selected = NO;
            str = [str stringByAppendingString:[NSString stringWithFormat:@"%zd",button.tag]];
        }
        NSLog(@"你想要的结果是 : %@",str);
        [self.buttonArray removeAllObjects];
        self.currentP = CGPointMake(0, 0);
        [self setNeedsDisplay];
        
        
        
    }
    
    /**
     通过一个点来获取button
    
     @param point 点
     @return 按钮
     */
    - (UIButton *)getButtonThroughPoint:(CGPoint)point {
        for (UIButton *button in self.subviews) {
            if (CGRectContainsPoint(button.frame, point)) {
                return button;
            }
        }
        return nil;
    }
    /**
     通过touches来获得当前的点
    
     @param touches touches
     @return 获取的点
     */
    - (CGPoint )getPointWithTouchs:(NSSet <UITouch *> *)touches {
        UITouch *touch = [touches anyObject];
        return [touch locationInView:self];
    }
    
    /**
     开始绘制
    
     @param rect 矩形
     */
    - (void)drawRect:(CGRect)rect {
        
        if (self.buttonArray.count == 0) {
            return;
        }
        
        UIBezierPath *path = [UIBezierPath bezierPath];
        for (NSInteger index = 0; index < self.buttonArray.count; index ++) {
            UIButton *button = (UIButton *)self.buttonArray[index];
            if (index == 0) {
                [path moveToPoint:button.center];
            }else {
                [path addLineToPoint:button.center];
            }
        }
        if (self.currentP.x > 0) {
           [path addLineToPoint:self.currentP];
        }
        [[UIColor greenColor] set];
        path.lineWidth = 5;
        [path setLineJoinStyle:kCGLineJoinRound];
        [path stroke];
        
    }
    
    @end
    
    1.png
    • 涂鸦的功能
    // drawView的.h 文件
    #import <UIKit/UIKit.h>
    
    @interface DrawView : UIView
    
    /**
     显示的imageview
     */
    @property (nonatomic,weak)IBOutlet UIImageView *displayImageView;
    /**
     颜色
     */
    @property (strong, nonatomic) UIColor *color;
    
    /**
     宽度
     */
    @property (assign, nonatomic) CGFloat width;
    /**
      清除的操作
     */
    - (void)clearAction;
    /**
      撤销的操作
     */
    - (void)undoAction;
    /**
     橡皮擦的事件
     */
    - (void)eraserAction;
    
    @end
    // drawView的.m文件
    
    #import "DrawView.h"
    #import "DrawBezierPath.h"
    
    @interface DrawView ()
    
    @property (strong, nonatomic) DrawBezierPath *drawPath;
    @property (strong, nonatomic) NSMutableArray *pathArray;
    
    
    
    @end
    @implementation DrawView
    -(NSMutableArray *)pathArray {
        if (!_pathArray) {
            _pathArray = [NSMutableArray array];
        }
        return _pathArray;
    }
    - (void)awakeFromNib {
        [super awakeFromNib];
        // 添加拖拽的事件
        UIPanGestureRecognizer *panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
        [self addGestureRecognizer:panGes];
    }
    
    /**
     手势拖拽的响应
    
     @param panGesture 拖拽手势
     */
    - (void)panAction:(UIPanGestureRecognizer *)panGesture{
        
        if (panGesture.state == UIGestureRecognizerStateBegan) {
            self.drawPath = [DrawBezierPath bezierPath];
            CGPoint currentPoint = [panGesture locationInView:self];
            [self.drawPath moveToPoint:currentPoint];
            _width > 0 ? (self.drawPath.lineWidth = _width):(self.drawPath.lineWidth = 1);
            _color != nil ? (self.drawPath.pathColor = _color) : (self.drawPath.pathColor = [UIColor blackColor]);
            [self.pathArray addObject:self.drawPath];
        }else if (panGesture.state == UIGestureRecognizerStateChanged){
            CGPoint currentPoint = [panGesture locationInView:self];
            [self.drawPath addLineToPoint:currentPoint];
        }
        [self setNeedsDisplay];
    }
    
    #pragma mark - 外部事件的响应
    /**
     清除的操作
     */
    - (void)clearAction{
        [self.pathArray removeAllObjects];
        [self setNeedsDisplay];
    }
    /**
     撤销的操作
     */
    - (void)undoAction {
        [self.pathArray removeLastObject];
        [self setNeedsDisplay];
    }
    /**
     橡皮擦的事件
     */
    - (void)eraserAction{
        self.color = self.backgroundColor;
        [self setNeedsDisplay];
    }
    
    /**
     设置颜色
     
     @param color 颜色
     */
    - (void)setColor:(UIColor *)color{
        _color = color;
        [self setNeedsDisplay];
    }
    /**
     设置宽度
     
     @param width 宽度
     */
    - (void)setWidth:(CGFloat)width{
        _width = width;
        [self setNeedsDisplay];
    }
    
    /**
     绘制上下文的部分
    
     @param rect 当前的上下文的区域
     */
    - (void)drawRect:(CGRect)rect {
        
        for (DrawBezierPath *path in self.pathArray) {
            [path.pathColor set];
            [path stroke];
        }
    }
    
    @end
    // DrawBezierPath.h文件 
    #import <UIKit/UIKit.h>
    
    @interface DrawBezierPath : UIBezierPath
    @property (strong, nonatomic) UIColor *pathColor;
    
    
    @end
    // DrawBezierPath.m文件 
    #import "DrawBezierPath.h"
    
    @implementation DrawBezierPath
    
    @end
    
    1.png
    • CALayer
    • layer 和view的区别:
      1)view可以处理事件的响应,而layer是用来显示,不能处理事件
      2)每个UIView都有一个layer提供内容的绘制与显示,并且UIView的尺寸和样式都由CALayer所提供,两者都是树形结构,layer 有一个SubLayers view有一个SubViews,但是layer比view多一个anchorPoint
      3)其实个人理解view的frame都是由本身的layer的frame确定的
      4)看这个链接view和layer的区别
        //  阴影的透明度,默认是完全透明的也就是0
        self.redView.layer.shadowOpacity = 1.0;
        //  设置阴影的颜色
        self.redView.layer.shadowColor = [UIColor greenColor].CGColor;
        //  设置阴影的偏移量
        self.redView.layer.shadowOffset = CGSizeMake(50, -50);
        //  设置阴影的模糊程度
        self.redView.layer.shadowRadius = 10;
    
    1.png
    • 两种方式显示图片
       // 第一种方式显示图片
        self.redView.layer.contents = (id)[UIImage imageNamed:@"timg"].CGImage;
        self.redView.layer.cornerRadius = 50;
        self.redView.layer.masksToBounds = YES;
        // 第二种方式显示图片
        self.displayImageView.layer.cornerRadius = 50;
        self.displayImageView.layer.masksToBounds = YES;
    
    1.png
    • uiimageview也是继承view 为什么在下面的这段代码中 view就被裁剪了而imagview 没有变化 因为图片显示的是在layer的内容层上 第一个代码没有显示内容 所以可以被裁剪,如果两段代码都加上layer.masksToBounds = YES就起作用了 因为masksToBounds是裁剪根试图以及根上的所有的内容进行裁剪
        // 第一种方式显示,可以裁剪
        self.redView.layer.cornerRadius = 50;
        // 第二种方式显示
        self.displayImageView.layer.cornerRadius = 50;
    
    1.png
    • 图片3d的平移、缩放、旋转
    [UIView animateWithDuration:1.0 animations:^{
     // 第一种方式
            // 3d的类型缩放
            self.displayImageView.layer.transform = CATransform3DMakeScale(1.5, 1.8, 3.0);
            // 3d类型旋转
            self.displayImageView.layer.transform = CATransform3DMakeRotation(M_PI, 1.0, 1.0, 1.0);
            // 3d类型旋转
            self.displayImageView.layer.transform = CATransform3DMakeTranslation(100, 100, 100);
     // 第二种方式
            [self.displayImageView.layer setValue:[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.5, 1.8, 3.0)] forKeyPath:@"transform"];
            [self.displayImageView.layer setValue:[NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 1.0, 1.0, 1.0)] forKeyPath:@"transform"];
            [self.displayImageView.layer setValue:[NSValue valueWithCATransform3D:CATransform3DMakeTranslation(100, 100, 100)] forKeyPath:@"transform"];
      // 第三种方式 简单快速的实现 kvc 这种方式实现
            [self.displayImageView.layer setValue:@(1.5) forKeyPath:@"transform.scale"];
            [self.displayImageView.layer setValue:@(M_PI) forKeyPath:@"transform.rotation"];
            [self.displayImageView.layer setValue:@(150) forKeyPath:@"transform.translation.x"];
    
        }];
    
    1.png
    • position 和anchorPosition的区别和联系
    • 解释anthorPosition 是图层的点默认在position的显示的位置,anchorPosition默认的是(0.5,0.5)范围是(0-1)表示图层的宽高比
    • 这两段代码是相同的
        CALayer *layer = [[CALayer alloc] init];
        layer.frame = CGRectMake(0, 0, 100, 100);
        layer.backgroundColor = [UIColor redColor].CGColor;
        [self.view.layer addSublayer:layer];
    
         CALayer *layer = [[CALayer alloc] init];
        layer.frame = CGRectMake(0, 0, 100, 100);
        layer.backgroundColor = [UIColor redColor].CGColor;
        layer.anchorPoint = CGPointMake(0.5, 0.5);
        [self.view.layer addSublayer:layer];
    
    • position 在0 和anchorPosition 在(0.5,0.5)
     CALayer *layer = [[CALayer alloc] init];
        layer.frame = CGRectMake(0, 0, 100, 100);
        layer.backgroundColor = [UIColor redColor].CGColor;
        layer.anchorPoint = CGPointMake(0.5, 0.5);
        layer.position = CGPointMake(0, 0);
        [self.view.layer addSublayer:layer];
    
    1.png
    • position 在(30,50) 和anchorPosition 在(0,0)
     CALayer *layer = [[CALayer alloc] init];
        layer.frame = CGRectMake(0, 0, 100, 100);
        layer.backgroundColor = [UIColor redColor].CGColor;
        layer.anchorPoint = CGPointMake(0, 0);
        layer.position = CGPointMake(30,50);
        [self.view.layer addSublayer:layer];
    
    1.png
    • 隐式动画
    • 自己的理解:他是系统非根层的动画,有我们自己创建的layer像改变position 、bounds、还有backgroundColor 等等的会存在默认的动画,原因是系统会创建一个包装的对象对他们进行包装,包装完毕才会执行改变
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        CALayer *layer = [[CALayer alloc] init];
        layer.frame = CGRectMake(0, 0, 100, 100);
        layer.backgroundColor = [UIColor redColor].CGColor;
        layer.anchorPoint = CGPointMake(0, 0);
        layer.position = CGPointMake(30,50);
        self.layer = layer;
        [self.view.layer addSublayer:layer];
    }
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        
        [CATransaction begin];
        // 取消动画
        [CATransaction setDisableActions:YES];
        // 设置动画的时常
        [CATransaction setAnimationDuration:5.0];
        self.layer.backgroundColor = [UIColor greenColor].CGColor;
        self.layer.position = CGPointMake(100, 200);
        [CATransaction commit];
        
    }
    
    • 心跳动画 主要是CABasicAnimation的使用
    • 一些属性的说明(他的主要作用是 平移、旋转、缩放这些)
      duration 动画的时间
      repeatCount 重复的次数。不停重复设置为 HUGE_VALF
      repeatDuration 设置动画的时间。
      beginTime 指定动画开始的时间。从开始延迟几秒的话,设置为【CACurrentMediaTime() + 秒数】 的方式
      timingFunction 设置动画的速度变化
      autoreverses 动画结束时是否执行逆动画
      fromValue 所改变属性的起始值
      toValue 所改变属性的结束时的值
      byValue 所改变属性相同起始值的改变量
    • 心跳动画
     CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
        animation.duration = 1.5;
        animation.fromValue = @(0);
        animation.toValue = @(2);
        // 无限重复
        animation.repeatCount = NSIntegerMax;
        // 自动恢复原来的位置(有一个恢复的动画)
        animation.autoreverses = YES;
        // 确定完成后动画是否从目标图层的动画中移除。
        // 当“是”时,一旦活动持续时间过去,动画将从目标图层的动画中移除。 默认为YES
        animation.removedOnCompletion = NO;
        [self.heartimageView.layer addAnimation:animation forKey:nil];
    
    • 移动的动画
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
        animation.duration = 2;
        animation.repeatCount = NSIntegerMax;
        animation.beginTime =CACurrentMediaTime() + 1;// 1秒后执行
        
        animation.fromValue = [NSValue valueWithCGPoint:self.heartimageView.layer.position]; // 起始帧
        
        animation.toValue = [NSValue valueWithCGPoint:CGPointMake(300, 300)]; // 终了帧
        
        // 视图添加动画
        
        [self.heartimageView.layer addAnimation:animation forKey:@"move-layer"];
    
    • 旋转的动画
     // 对Y轴进行旋转(指定Z轴的话,就和UIView的动画一样绕中心旋转)
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
        animation.duration = 2;
        
        animation.repeatCount = NSIntegerMax;
        
        animation.beginTime = CACurrentMediaTime() + 1; // 1秒后执行
        
        animation.fromValue = [NSNumber numberWithFloat:0.0]; // 起始角度
        // 动画结束后停在最后位置状态的解决方法
        animation.removedOnCompletion = NO;
        animation.fillMode = kCAFillModeForwards;
        
        animation.toValue = [NSNumber numberWithFloat:M_PI]; // 终止角度
        
        [self.heartimageView.layer addAnimation:animation forKey:@"rotate-layer"];
    
    • 透明度的动画
    //opacity 指layer的透明度
        
        CABasicAnimation *basicAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
        
        basicAnimation.fromValue = @(1.0);
        
        basicAnimation.toValue  = @(0.0);//[NSNumber numberWithFloat:0.0]
        
        basicAnimation.duration = 1.5;
        
        [self.heartimageView.layer addAnimation:basicAnimation forKey:@"op"];
    
    • CAKeyframeAnimation 这个是线性的动画
    • 实现 一个图片绕着圆旋转
     CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 100, 100)];
        animation.path = path.CGPath;
        animation.duration = 3.0;
        animation.repeatCount = NSIntegerMax;
        // 自动恢复原位
        animation.autoreverses = YES;
        //  动画结束后停在最后位置状态的解决方法
        animation.removedOnCompletion = NO;
        animation.fillMode = kCAFillModeForwards;
        // 线性起搏,可使动画在其持续时间内均匀发生
        // kCAMediaTimingFunctionEaseInEaseOut: 轻松放松起搏,可以使动画开始缓慢,在其持续时间的中间加速,然后在完成之前再次放慢速度。
        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        [self.heartimageView.layer addAnimation:animation forKey:nil];
    
    • 图片的抖动
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
        animation.values = @[@(angele(-10)),@(angele(0))];
        animation.duration = 1.0;
        animation.repeatCount = NSIntegerMax;
        // 自动恢复原位
        animation.autoreverses = YES;
        //  动画结束后停在最后位置状态的解决方法
        animation.removedOnCompletion = NO;
        animation.fillMode = kCAFillModeForwards;
        // 线性起搏,可使动画在其持续时间内均匀发生
        // kCAMediaTimingFunctionEaseInEaseOut: 轻松放松起搏,可以使动画开始缓慢,在其持续时间的中间加速,然后在完成之前再次放慢速度。
        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        [self.heartimageView.layer addAnimation:animation forKey:nil];
    
    • 转场动画 (CATransition)
    • 图片的翻页效果
      index_ ++;
        if (index_ > 3 ) {
            index_ = 1;
        }
        NSString *imageName = [NSString stringWithFormat:@"%d",index_];
        self.heartimageView.image = [UIImage imageNamed:imageName];
        
        CATransition *animation = [CATransition animation];
        /*
         type:动画过渡类型
         subtype:动画过渡方向
         startProgress:动画起点(在整体动画的百分比)
         endProgress:动画终点(在整体动画的百分比)
         */
         // 动画的过度类型
       // animation.type = kCATransitionMoveIn;
        // 或者这个方式也行
        /*
         关于type的总结 后面的一张图片
         */
        animation.type = @"pageCurl";
         // 动画的过度方向
        animation.subtype = kCATransitionFromRight;
        animation.startProgress = 0.1;
        animation.endProgress = 0.7;
        [self.heartimageView.layer addAnimation:animation forKey:nil];
    
    • 关于type的总结


      1.jpg
    • CATransition的另外一种使用
      自带的动画
    [UIView transitionWithView:self.heartimageView duration:2.0 options:UIViewAnimationOptionTransitionFlipFromBottom animations:^{
            index_ ++;
            if (index_ > 3 ) {
                index_ = 1;
            }
            NSString *imageName = [NSString stringWithFormat:@"%d",index_];
            self.heartimageView.image = [UIImage imageNamed:imageName];
        } completion:nil];
    
    • 自带动画2
    //  前台页面
        UIView *frontView = [[UIView alloc] initWithFrame:self.view.bounds];
        frontView.backgroundColor = [UIColor colorWithRed:0.345 green:0.349 blue:0.365 alpha:1.000];
        UIImageView *caLogoView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"1"]];
        caLogoView.frame = CGRectMake(70, 80, caLogoView.bounds.size.width, caLogoView.bounds.size.height);
        [frontView addSubview:caLogoView];
        self.frontView = frontView;
        
        //  后台页面
        UIImage *backImage = [UIImage imageNamed:@"2"];
        UIImageView *backView = [[UIImageView alloc] initWithImage:backImage];
        backView.userInteractionEnabled = YES;
        self.backView = backView;
        
        [self.view addSubview:backView];
        [self.view addSubview:frontView];
     // formcview :在执行动画的过程中,他将会从superview 删除
        // toView :执行动画结束添加到fromview的父视图
        [UIView transitionFromView:self.frontView    // 从原来视图转到新视图的动画效果设置
                                toView:self.backView  duration:1.0f
                             options:UIViewAnimationOptionTransitionFlipFromLeft
                             completion:nil];
    
    • 动画组
     CAAnimationGroup *group = [CAAnimationGroup animation];
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
        animation.fromValue = @(0);
        animation.toValue = @(1.5);
        
        CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
        rotationAnimation.fromValue = @(0);
        rotationAnimation.toValue = @(M_PI);
        group.animations = @[animation,rotationAnimation];
        group.duration = 1.5;
        group.repeatCount = NSIntegerMax;
        group.removedOnCompletion = NO;
        group.fillMode = kCAFillModeForwards;
        [self.heartimageView.layer addAnimation:group forKey:nil];
    
    • UIView的动画和图层动画的区别是:
      1.涂层动画不能处理点击等等的事件,本身的frame并不改变。
      2.UIView的动画可以出点点击事件等等 完成与用户的交互。
    • 一个图片折叠的动画
    -(void)viewDidLoad {
        [super viewDidLoad];
        
        self.heartimageView.layer.contentsRect = CGRectMake(0, 0, 1, 0.5);
        self.bottomImageView.layer.contentsRect = CGRectMake(0, 0.5, 1, 0.5);
        
        self.heartimageView.layer.anchorPoint = CGPointMake(0.5, 1);
        self.bottomImageView.layer.anchorPoint = CGPointMake(0.5, 0);
        // 添加拖拽的手势
        UIPanGestureRecognizer *panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
        [self.view addGestureRecognizer:panGes];
        // 添加隐影的操作(梯度的layer )
        CAGradientLayer *grandientLayer = [CAGradientLayer layer];
        grandientLayer.frame = self.bottomImageView.bounds;
        grandientLayer.colors = @[(id)[UIColor blackColor].CGColor,(id)[UIColor clearColor].CGColor];
        // 确定颜色的渐变方向
        grandientLayer.startPoint = CGPointMake(0, 0);
        grandientLayer.endPoint = CGPointMake(1.0, 1.0);
        // 一个颜色到下一个颜色开始渐变的位置
        grandientLayer.locations = @[@(0.2),@(0.8)];
        // 暗影
        grandientLayer.shadowOpacity = 0.0;
        // 不透明度
        grandientLayer.opacity = 0.0;
        self.grandientLayer = grandientLayer;
        [self.bottomImageView.layer addSublayer:grandientLayer];
    }
    /**
     添加拖拽的手势
    
     @param panGes 手势的点击
     */
    - (void)panAction:(UIPanGestureRecognizer *)panGes {
        
        CGPoint point = [panGes locationInView:self.view];
        CGFloat angle =  M_PI * 1.0 * point.y /self.view.bounds.size.height;
        
        CATransform3D transform = CATransform3DIdentity;
        // 立体效果 离你眼睛越近 看的越清楚 离你眼睛越远 看的越小
        transform.m34 = -1.0/500.0;
        self.heartimageView.layer.transform = CATransform3DRotate(transform, -angle, 1.0, 0, 0);
        // 改变透明度
        self.grandientLayer.opacity = 1.0 * point.y /self.view.bounds.size.height;
        
        
        // 结束了进行反弹回去
        if (panGes.state == UIGestureRecognizerStateEnded) {
            // 一个动画
            // delay:动画开始时的等待时间,默认为0
            // usingSpringWithDamping: 反弹系数
            // initialSpringVelocity:动画的速度
            [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.5 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
                // 去掉所有的动画 回去
                self.heartimageView.layer.transform = CATransform3DIdentity;
                self.grandientLayer.opacity = 0.0;
            } completion:nil];
        }
    }
    
    1.png
    • 音乐震动条(类似于网易云音乐)
      音乐震动条
    • 利用 制作到影的动画
        CAReplicatorLayer *replicatorLayer = (CAReplicatorLayer *)self.view.layer;
        replicatorLayer.instanceCount = 2;
        //CAReplicatorLayer 旋转是按照本身的锚点来进行旋转的(这里是屏幕的正中央)
        replicatorLayer.instanceTransform = CATransform3DMakeRotation(M_PI, 1, 0, 0);   
        // 绘制阴影
        replicatorLayer.instanceRedOffset -= 0.1;
        replicatorLayer.instanceBlueOffset -= 0.1;
        replicatorLayer.instanceGreenOffset -= 0.1;
        // 透明度
        replicatorLayer.instanceAlphaOffset -= 0.1; 
    
    2.png
    1.png
    • 一个根据线条变化的动画
    DrewView.h文件
    
    /**
     开始的事件
     */
    - (void)startAction;
    /**
     重绘的方法
     */
    - (void)redrewAction;
    
    DrewView.m 文件
    //
    //  DrewView.m
    //  基本动画的练习
    //
    //  Created by apple on 2018/3/19.
    //  Copyright © 2018年 apple. All rights reserved.
    //
    
    #import "DrewView.h"
    
    @interface DrewView ()
    
    @property (strong, nonatomic) UIBezierPath *path;
    @property (strong, nonatomic) CALayer *myLayer;
    @property (strong, nonatomic) CAReplicatorLayer *replicatorLayer;
    
    
    @end
    
    @implementation DrewView
    
    -(void)awakeFromNib {
        [super awakeFromNib];
        
        // 创建一个path
        UIBezierPath *path = [UIBezierPath bezierPath];
        self.path = path;
        // 创建手势
        UIPanGestureRecognizer *panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
        [self addGestureRecognizer:panGes];
        
        // 创建一个layer
        CALayer *myLayer = [[CALayer alloc] init];
        myLayer.frame = CGRectMake(-10, 0, 10, 10);
        myLayer.cornerRadius = 5;
        myLayer.backgroundColor = [UIColor redColor].CGColor;
        self.myLayer = myLayer;
        // 创建复制层
        CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
        replicatorLayer.instanceDelay = 0.25;
        [replicatorLayer addSublayer:self.myLayer];
        [self.layer addSublayer:replicatorLayer];
        self.replicatorLayer = replicatorLayer;
        
    }
    
    /**
     拖拽的手势
    
     @param panGes 手势
     */
    - (void)panAction:(UIPanGestureRecognizer *)panGes{
        
        CGPoint currentPoint = [panGes locationInView:self];
        if (panGes.state == UIGestureRecognizerStateBegan) {
          [self.path moveToPoint:currentPoint];
        }else if (panGes.state == UIGestureRecognizerStateChanged){
            [self.path addLineToPoint:currentPoint];
            [self setNeedsDisplay];
        }else if (panGes.state == UIGestureRecognizerStateEnded){
            [self setNeedsDisplay];
        }
    }
    /**
     开始绘制
    
     @param rect rect
     */
    -(void)drawRect:(CGRect)rect {
        [self.path stroke];
        
    }
    /**
     开始的事件
     */
    - (void)startAction{
        // 创建动画
        CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        animation.path = self.path.CGPath;
        animation.duration = 1.0;
        animation.repeatCount = NSIntegerMax;
        // 自动复位
        animation.autoreverses = YES;
        // 消除停在最后的位置
        animation.removedOnCompletion = NO;
        animation.fillMode = kCAFillModeForwards;
        // 动画匀速
        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        [self.myLayer addAnimation:animation forKey:nil];
        // 复制层
        self.replicatorLayer.instanceCount = 30;
    //    self.replicatorLayer.instanceTransform = CATransform3DMakeTranslation(0, 2, 0);
        
    }
    /**
     重绘的方法
     */
    - (void)redrewAction{
        [self.path removeAllPoints];
        [self.myLayer removeAllAnimations];
        [self setNeedsDisplay];
    }
    @end
    
    IMG_0819.GIF
    • qq 粘性动画
    bagdeButton.h文件
    #import <UIKit/UIKit.h>
    
    @interface bagdeButton : UIButton
    
    @end
    bagdeButton.m文件
    #import "bagdeButton.h"
    
    
    @interface bagdeButton ()
    
    @property (strong, nonatomic) UIView *smallView;
    @property (strong, nonatomic) CAShapeLayer *shapeLayer;
    
    
    @end
    @implementation bagdeButton
    
    -(CAShapeLayer *)shapeLayer {
        if (!_shapeLayer) {
             // 创建根据路线显示涂层的层(形状图层)
            CAShapeLayer *shapeLayer = [CAShapeLayer layer];
            shapeLayer.fillColor = [UIColor redColor].CGColor;
            [self.superview.layer insertSublayer:shapeLayer atIndex:0];
            _shapeLayer = shapeLayer;
        }
        return _shapeLayer;
    }
    
    
    -(void)awakeFromNib {
        [super awakeFromNib];
        // 初始化
        [self setUp];
        
    }
    -(instancetype)initWithFrame:(CGRect)frame {
        if (self = [super initWithFrame:frame]) {
            // 初始化
            [self setUp];
        }
        return self;
    }
    /**
     初始化
     */
    - (void)setUp{
        
        // 本身的基本的设置
        self.layer.cornerRadius = self.bounds.size.width *0.5;
        self.layer.masksToBounds = YES;
        self.titleLabel.textColor = [UIColor whiteColor];
        self.backgroundColor = [UIColor redColor];
        self.titleLabel.font = [UIFont systemFontOfSize:12.0];
        // 添加拖拽的手势
        UIPanGestureRecognizer *panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
        [self addGestureRecognizer:panGes];
        // 添加小圆
        UIView *smallView = [[UIView alloc] initWithFrame:self.frame];
        smallView.backgroundColor = [UIColor redColor];
        smallView.layer.cornerRadius = self.bounds.size.width *0.5;
        self.smallView = smallView;
        [self.superview insertSubview:smallView belowSubview:self];
       
    }
    /**
     拖拽的手势
    
     @param panGes 手势
     */
    - (void)panAction:(UIPanGestureRecognizer *)panGes {
        
        // 当前weiz的偏移量
        CGPoint panOff = [panGes locationInView:self.superview];
        CGRect frame = self.frame;
        frame.origin = panOff;
        self.frame = frame;
        
        
        // 计算两个圆直接的距离
        CGFloat dx1 = self.frame.origin.x - self.smallView.frame.origin.x;
        CGFloat dy1 = self.frame.origin.y - self.smallView.frame.origin.y;
        // 相当于求三角形的斜边
        CGFloat d = hypotf(dx1, dy1);
        // 改变小圆的frame
        CGRect smallRect = self.smallView.frame;
        CGFloat calculatorWidth = self.frame.size.width - self.frame.size.width *(1.0 * d/60);
        if (calculatorWidth <= 0) {
            calculatorWidth = 0;
        }
        smallRect.size.width = calculatorWidth;
        smallRect.size.height = calculatorWidth;
        self.smallView.frame = smallRect;
        self.smallView.layer.cornerRadius = calculatorWidth * 0.5;
        UIBezierPath *path = [self pathWithSmallView:self.smallView andBigView:self andRadius:d];
        self.shapeLayer.path = path.CGPath;
        
        if (panGes.state == UIGestureRecognizerStateEnded) {
            if (d < 60) {
                CGRect frame = self.frame;
                frame.origin = self.smallView.frame.origin;
                self.frame = frame;
                [self.shapeLayer removeFromSuperlayer];
                self.smallView.frame = self.frame;
                self.smallView.layer.cornerRadius = self.frame.size.width * 0.5;
                self.smallView.hidden = NO;
            }else {
                [self.shapeLayer removeFromSuperlayer];
                self.smallView.hidden = YES;
              
                // 创建一个imageview 来进行一个爆炸的效果
                UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, 100, 100)];
                NSMutableArray *imagesArray = [NSMutableArray array];
                for (NSInteger index = 1; index < 4; index ++) {
                    NSString *imageName = [NSString stringWithFormat:@"%zd",index];
                    UIImage *image = [UIImage imageNamed:imageName];
                    [imagesArray addObject:image];
                }
                imageView.animationImages = imagesArray;
                [imageView startAnimating];
                [self.superview addSubview:imageView];
                // 移动从父试图
                [self removeFromSuperview];
                
            }
            
        }
    }
    /**
     根据小圆和大圆返回路径
     
     @param smallView 小圆
     @param bigButton 大圆
     @param d 半径
     @return 路径
     */
    - (UIBezierPath *)pathWithSmallView:(UIView *)smallView andBigView:(UIButton *)bigButton andRadius:(CGFloat )d{
        
        // 求各个点的值
        CGFloat x1 = smallView.center.x;
        CGFloat y1 = smallView.center.y;
        CGFloat x2 = bigButton.center.x;
        CGFloat y2 = bigButton.center.y;
        CGFloat r1 = smallView.frame.size.width * 0.5;
        CGFloat r2 = bigButton.frame.size.width * 0.5;
        
        CGFloat siny = (x2 - x1)/d;
        CGFloat cosy = (y1 - y2)/d;
        CGPoint A = CGPointMake(x1 - cosy*r1, y1 - siny*r1);
        CGPoint B = CGPointMake(x1 + cosy*r1, y1 + siny*r1);
        CGPoint C = CGPointMake(x2 - cosy*r2, y2 - siny*r2);
        CGPoint D = CGPointMake(x2 + cosy*r2, y2 + siny*r2);
        CGPoint P = CGPointMake(A.x + siny*d/2.0, A.y - cosy*d/2.0);
        CGPoint O = CGPointMake(B.x + siny*d/2.0, B.y - cosy*d/2.0);
        UIBezierPath *path = [UIBezierPath bezierPath];
        [path moveToPoint:A];
        // 曲线
        [path addQuadCurveToPoint:C controlPoint:P];
        [path addLineToPoint:D];
        // 曲线
        [path addQuadCurveToPoint:B controlPoint:O];
        [path addLineToPoint:A];
        return path;
    }
    
    50B1870FAF9F924745754B4BE3836F2E.png
    • 微博的动画(类似与点击微博的➕)
    WeiBoViewController.h文件
    #import <UIKit/UIKit.h>
    
    @interface WeiBoViewController : UIViewController
    
    @end
     WeiBoViewController.m文件
    #import "WeiBoViewController.h"
    
    @interface WeiBoViewController ()
    
    @property (strong, nonatomic) NSMutableArray *buttonArray;
    @property (strong, nonatomic) NSTimer *timer;
    @property (assign, nonatomic) int index;
    
    
    @end
    @implementation WeiBoViewController
    -(NSMutableArray *)buttonArray {
        if (!_buttonArray) {
            _buttonArray = [NSMutableArray array];
        }
        return _buttonArray;
    }
    - (void)viewDidLoad {
        [super viewDidLoad];
        // 初始化
        [self setUp];
        self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(timerChange) userInfo:nil repeats:YES];
    }
    
    /**
     定时器改变的方法
     */
    - (void)timerChange{
        if (self.index == self.buttonArray.count) {
            [self.timer invalidate];
            self.timer = nil;
            return;
        }
        UIButton *button = self.buttonArray[self.index];
        // 这个动画有弹性效果
        [UIView animateWithDuration:0.2 delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            // 恢复开始的样子
            button.transform = CGAffineTransformIdentity;
        } completion:nil];
        self.index ++;
    }
    
    
    /**
     初始化
     */
    - (void)setUp{
        
        int row = 0;
        int column = 0;
        for (NSInteger index = 0; index < 6; index++) {
            UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
            row = (int)index/3;
            column = (int)index%3;
            button.backgroundColor = [UIColor redColor];
            button.frame = CGRectMake(10 + column*(80 + 20), 467 + row*(80+20), 80, 80);
            [button setTitle:@"微博"forState:UIControlStateNormal];
            [self.view addSubview:button];
            [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchDown];
            [button addTarget:self action:@selector(buttonClickUpInside:) forControlEvents:UIControlEventTouchUpInside];
            // 移动到最底部
            button.transform = CGAffineTransformMakeTranslation(button.frame.origin.x, self.view.bounds.size.height);
            [self.buttonArray addObject:button];
        }
    }
    
    /**
     按钮按下事件
    
     @param button 按钮
     */
    - (void)buttonClick:(UIButton *)button{
     
        button.transform = CGAffineTransformMakeScale(1.2, 1.2);
    }
    /**
     按钮按下抬起
    
     @param button 按钮
     */
    - (void)buttonClickUpInside:(UIButton *)button {
        
        [UIView animateWithDuration:1.0 animations:^{
            button.transform = CGAffineTransformMakeScale(2, 2);
        }completion:^(BOOL finished) {
            button.alpha = 0;
        }];
    }
    @end
    
    1.png
    • 例子效果
     // 创建粒子效果的layer
        CAEmitterLayer *emiterLayer = [[CAEmitterLayer alloc] init];
        // 创建发射器的位置
        emiterLayer.position = CGPointMake(self.view.bounds.size.width * 0.5, 100);
        // 开启三维的效果
        emiterLayer.preservesDepth = YES;
        // 创建每一个cell 并且给每一个cell添加属性
        CAEmitterCell *cell = [[CAEmitterCell alloc] init];
        // 设置粒子的速度
        cell.velocity = 100;
        cell.velocityRange = 50;
        // 例子的大小 scaleRange:(相当于scale 是 1.2 - 0.2)
        cell.scale = 0.7;
        cell.scaleRange = 0.5;
        // 粒子的方向
        cell.emissionLongitude = M_PI_2;
        cell.emissionRange = 0.5 * M_PI_2;
        // 设置每一秒弹出多少个
        cell.birthRate = 10;
        // 设置例子的旋转
        cell.spin = M_PI_2;
        cell.spinRange = M_PI_2;
        // 例子的存活时间
        cell.lifetime = 5;
        cell.lifetimeRange = 3;
        // 设置粒子的图片
        cell.contents = (id)[UIImage imageNamed:@"good6_30x30_"].CGImage;
        emiterLayer.emitterCells = @[cell];
        [self.view.layer addSublayer:emiterLayer];
    
    image.png
    • 补充 CAShapeLayer
    • 作用 :根据路径显示图形
      链接
    • 终于总结完了 花了我两个星期的时间,如果大家感觉有什么不对的,千万给予指正,我将不胜荣幸!

    相关文章

      网友评论

        本文标题:quartz 2d

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