长路漫漫,唯剑作伴--Core Animation

一、UIView和CALayer

  1. 关系

    • 在创建UIView对象时,UIView内部会自动创建一个层(即CALayer对象),通过UIView的layer属性可以访问这个层。当UIView需要显示到屏幕上时,会调用drawRect:方法进行绘图,并且会将所有内容绘制在自己的层上,绘图完毕后,系统会将层拷贝到屏幕上,于是就完成了UIView的显示。
    • 换句话说,UIView本身不具备显示的功能,是它内部的层才有显示功能。
    • 两者都有树状层级结构,layer 内部有 SubLayers,View 内部有 SubViews.但是 Layer 比 View 多了个AnchorPoint
  2. 不同

    • 两者最明显的区别是 View可以接受并处理事件,而 Layer 不可以.
    • UIView主要是对显示内容的管理而 CALayer 主要侧重显示内容的绘制。
    • 在做 iOS 动画的时候,修改非 RootLayer的属性(譬如位置、背景色等)会默认产生隐式动画,而修改UIView则不会。
  3. 修改CALayer的属性

    - (IBAction)changeCorners:(UIButton *)sender {
        self.layer.cornerRadius = (self.layer.cornerRadius == 0.0f) ? 30.0f : 0.0f;
        NSLog(@"%@",sender.nextResponder);
    }
    - (IBAction)changeOpacity:(UIButton *)sender {
        self.layer.opacity = (self.layer.opacity == 1.0f) ? 0.8f : 1.0f;
    }
    - (IBAction)changeBorders:(UIButton *)sender {
        self.layer.borderWidth = (self.layer.borderWidth == 10) ? 0 : 10;
    }
    - (IBAction)changeColors:(UIButton *)sender {
        self.layer.backgroundColor = (self.layer.backgroundColor == [UIColor blueColor].CGColor) ? [UIColor redColor].CGColor : [UIColor blueColor].CGColor;
    }
    - (IBAction)changePositon:(UIButton *)sender {
        self.layer.position = (self.layer.position.x == 207) ? CGPointMake(300, 368) : CGPointMake(207, 368);
    }
    - (IBAction)changeBounds:(UIButton *)sender {
        self.layer.bounds = (self.layer.bounds.size.width == 100) ? CGRectMake(0, 0, 150, 100) : CGRectMake(0, 0, 100, 100);
    }
    - (IBAction)changeTransform:(UIButton *)sender {
        self.layer.transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);
    }

二、Core Animation

  1. CABasicAnimation

    - (IBAction)translation:(UIButton *)sender {
        CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"];
        anim.delegate = self;
        anim.duration = 1.5;
        anim.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 300)];
    //    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    //    anim.removedOnCompletion = NO;
    //    anim.fillMode = kCAFillModeForwards;
        [self.redView.layer addAnimation:anim forKey:@"ppposition"];
    }
    - (void)translation {
        CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform"];
        anim.delegate = self;
        anim.duration = 1.5;
        CATransform3D form = CATransform3DMakeTranslation(200, 300, 0);
        anim.toValue = [NSValue valueWithCATransform3D:form];
    //    anim.removedOnCompletion = NO;
    //    anim.fillMode = kCAFillModeForwards;
        [self.redView.layer addAnimation:anim forKey:@"position"];
    }
    - (IBAction)scale:(UIButton *)sender {
        CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"bounds"];
        anim.duration = 1.5;
        anim.delegate = self;
        anim.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 200, 200)];
        [self.redView.layer addAnimation:anim forKey:@"ssscale"];
    }
    - (void)scale {
        CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform"];
        anim.delegate = self;
        anim.duration = 1.5;
        anim.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1, 1)];
        anim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(2, 2, 1)];
        [self.redView.layer addAnimation:anim forKey:nil];
    }
    - (IBAction)rotation:(UIButton *)sender {
        CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform"];
        anim.duration = 1.5;
        anim.delegate = self;
        anim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_4, 0, 0, 1)];
        [self.redView.layer addAnimation:anim forKey:nil];
    }
    
    - (void)animationDidStart:(CAAnimation *)anim {
        NSLog(@"____animation start");
    }
    - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
        NSLog(@"____animation done");
    }
  2. CAKeyframeAnimation

    - (IBAction)points:(UIButton *)sender {
        CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        anim.duration = 1.5;
        anim.delegate = self;
        NSValue *v1 = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
        NSValue *v2 = [NSValue valueWithCGPoint:CGPointMake(200, 100)];
        NSValue *v3 = [NSValue valueWithCGPoint:CGPointMake(200, 200)];
        NSValue *v4 = [NSValue valueWithCGPoint:CGPointMake(100, 200)];
        anim.values = @[v1, v2, v3, v4];
        [self.redView.layer addAnimation:anim forKey:@""];
    }
    - (IBAction)path:(UIButton *)sender {
        CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        anim.duration = 1.5;
        anim.delegate = self;
        CGMutablePathRef path = CGPathCreateMutable();
        CGPathAddEllipseInRect(path, NULL, CGRectMake(100, 100, 300, 300));
        anim.path = path;
        [self.redView.layer addAnimation:anim forKey:@""];
    }
    - (void)animationDidStart:(CAAnimation *)anim {
        NSLog(@"____start");
    }
    - (void)animationDidStop:(CAAnimation *)anim {
        NSLog(@"____done");
    }
  3. CAAnimationGroup

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        CABasicAnimation *scale = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
        scale.toValue = @(0.0);
    
        CABasicAnimation *move = [CABasicAnimation animationWithKeyPath:@"transform.translation"];
        move.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 200)];
    
        CABasicAnimation *rotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
        rotation.toValue = @(M_PI);
    
        CAAnimationGroup *group = [CAAnimationGroup animation];
        group.duration = 2;
        group.delegate = self;
        group.animations = @[scale, move, rotation];
        [self.redView.layer addAnimation:group forKey:nil];
    }
    - (void)animationDidStart:(CAAnimation *)anim {
        NSLog(@"____start");
    }
    - (void)animationDidStop:(CAAnimation *)anim {
        NSLog(@"____done");
    }
  4. CATransition

    - (IBAction)pre:(UIButton *)sender {
        self.index--;
        if (self.index == 0) {
            self.index = 4;
        }
        NSString *name = [NSString stringWithFormat:@"%d.png",_index];
        self.imgView.image = [UIImage imageNamed:name];
        CATransition *anim = [CATransition animation];
        //    anim.type = @"cube";
        //    anim.subtype = kCATransitionFromLeft;
        anim.type = @"pageCurl";
        anim.duration = 0.5;
        [self.imgView.layer addAnimation:anim forKey:nil];
    
    }
    - (IBAction)nex:(UIButton *)sender {
        self.index++;
        NSLog(@"__%d",self.index);
        if (self.index == 5) {
            self.index = 1;
        }
        NSString *name = [NSString stringWithFormat:@"%d.png",_index];
        self.imgView.image = [UIImage imageNamed:name];
        CATransition *anim = [CATransition animation];
        //    anim.type = @"cube";
        //    anim.subtype = kCATransitionFromLeft;
        anim.type = @"pageUnCurl";
        anim.duration = 0.5;
        [self.imgView.layer addAnimation:anim forKey:nil];
    }

三、UIBezierPath

  1. ZYView.h

    #import <UIKit/UIKit.h>
    
    typedef NS_ENUM(NSUInteger, ZYBezierPathType) {
        kDefaultPath = 1, // 三角形
        kRectPath = 2, // 矩形
        kCirclePath = 3,//圆
        kOvalPath = 4, // 椭圆
        kRoundedRectPath = 5, // 带圆角的矩形
        kArcPath = 6, // 弧
        kSecondBezierPath = 7, // 二次贝塞尔曲线
        kThirdBezierPath = 8 // 三次贝塞尔曲线
    };
    
    @interface ZYView : UIView
    
    @property (nonatomic, assign)ZYBezierPathType type;
    
    @end
  2. ZYView.m

    #import "ZYView.h"
    
    @implementation ZYView
    
    - (void)drawRect:(CGRect)rect {
        switch (self.type) {
            case kDefaultPath: {// 三角形
                [self drawTrianglePath];
                break;
            }
            case kRectPath: {// 矩形
                [self drawRectPath];
                break;
            }
            case kCirclePath: {//圆
                [self drawCiclePath];
                break;
            }
            case kOvalPath: {// 椭圆
                [self drawOvalPath];
                break;
            }
            case kRoundedRectPath: {// 带圆角的矩形
                [self drawRoundedRectPath];
                break;
            }
            case kArcPath: {// 弧
                [self drawARCPath];
                break;
            }
            case kSecondBezierPath: {// 二次贝塞尔曲线
                [self drawSecondBezierPath];
                break;
            }
            case kThirdBezierPath: {// 三次贝塞尔曲线
                [self drawThirdBezierPath];
                break;
            }
            default: {
                break;
            }
        }
    }
    
    // 画三角形
    - (void)drawTrianglePath {
        UIBezierPath *path = [UIBezierPath bezierPath];
        [path moveToPoint:CGPointMake(20, 20)];
        [path addLineToPoint:CGPointMake(self.frame.size.width - 40, 20)];
        [path addLineToPoint:CGPointMake(self.frame.size.width / 2, self.frame.size.height - 20)];
    
        // 最后的闭合线是可以通过调用closePath方法来自动生成的,也可以调用-addLineToPoint:方法来添加
        //  [path addLineToPoint:CGPointMake(20, 20)];
    
        [path closePath];
    
        // 设置线宽
        path.lineWidth = 1.5;
    
        // 设置填充颜色
        UIColor *fillColor = [UIColor greenColor];
        [fillColor set];
        [path fill];
    
        // 设置画笔颜色
        UIColor *strokeColor = [UIColor blueColor];
        [strokeColor set];
    
        // 根据我们设置的各个点连线
        [path stroke];
    }
    
    // 画矩形
    - (void)drawRectPath {
        UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.height - 40)];
    
        path.lineWidth = 1.5;
        path.lineCapStyle = kCGLineCapRound;
        path.lineJoinStyle = kCGLineJoinBevel;
    
        // 设置填充颜色
        UIColor *fillColor = [UIColor greenColor];
        [fillColor set];
        [path fill];
    
        // 设置画笔颜色
        UIColor *strokeColor = [UIColor blueColor];
        [strokeColor set];
    
        // 根据我们设置的各个点连线
        [path stroke];
    }
    
    // 画圆
    - (void)drawCiclePath {
        // 传的是正方形,因此就可以绘制出圆了
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.width - 40)];
    
        // 设置填充颜色
        UIColor *fillColor = [UIColor greenColor];
        [fillColor set];
        [path fill];
    
        // 设置画笔颜色
        UIColor *strokeColor = [UIColor blueColor];
        [strokeColor set];
    
        // 根据我们设置的各个点连线
        [path stroke];
    }
    
    // 画椭圆
    - (void)drawOvalPath {
        // 传的是不是正方形,因此就可以绘制出椭圆圆了
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(20, 20, self.frame.size.width - 80, self.frame.size.height - 40)];
    
        // 设置填充颜色
        UIColor *fillColor = [UIColor greenColor];
        [fillColor set];
        [path fill];
    
        // 设置画笔颜色
        UIColor *strokeColor = [UIColor blueColor];
        [strokeColor set];
    
        // 根据我们设置的各个点连线
        [path stroke];
    }
    
    - (void)drawRoundedRectPath {
        //  UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.height - 40) cornerRadius:10];
    
        UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.height - 40) byRoundingCorners:UIRectCornerTopRight cornerRadii:CGSizeMake(20, 20)];
        // 设置填充颜色
        UIColor *fillColor = [UIColor greenColor];
        [fillColor set];
        [path fill];
    
        // 设置画笔颜色
        UIColor *strokeColor = [UIColor blueColor];
        [strokeColor set];
    
        // 根据我们设置的各个点连线
        [path stroke];
    }
    // 画弧
    #define   kDegreesToRadians(degrees)  ((pi * degrees)/ 180)
    - (void)drawARCPath {
        const CGFloat pi = 3.14159265359;
    
        CGPoint center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center
                                                            radius:100
                                                        startAngle:0
                                                          endAngle:kDegreesToRadians(135)
                                                         clockwise:YES];
    
        path.lineCapStyle = kCGLineCapRound;
        path.lineJoinStyle = kCGLineJoinRound;
        path.lineWidth = 5.0;
    
        UIColor *strokeColor = [UIColor redColor];
        [strokeColor set];
    
        [path stroke];
    }
    // 二次贝塞尔曲线
    - (void)drawSecondBezierPath {
        UIBezierPath *path = [UIBezierPath bezierPath];
    
        // 首先设置一个起始点
        [path moveToPoint:CGPointMake(20, self.frame.size.height - 100)];
    
        // 添加二次曲线
        [path addQuadCurveToPoint:CGPointMake(self.frame.size.width - 20, self.frame.size.height - 100)
                     controlPoint:CGPointMake(self.frame.size.width / 2, 0)];
    
        path.lineCapStyle = kCGLineCapRound;
        path.lineJoinStyle = kCGLineJoinRound;
        path.lineWidth = 5.0;
    
        UIColor *strokeColor = [UIColor redColor];
        [strokeColor set];
    
        [path stroke];
    }
    // 三次贝塞尔曲线
    - (void)drawThirdBezierPath {
        UIBezierPath *path = [UIBezierPath bezierPath];
    
        // 设置起始端点
        [path moveToPoint:CGPointMake(20, 150)];
    
        [path addCurveToPoint:CGPointMake(300, 150)
                controlPoint1:CGPointMake(160, 0)
                controlPoint2:CGPointMake(160, 250)];
    
        path.lineCapStyle = kCGLineCapRound;
        path.lineJoinStyle = kCGLineJoinRound;
        path.lineWidth = 5.0;
    
        UIColor *strokeColor = [UIColor redColor];
        [strokeColor set];
    
        [path stroke];
    }
    
    @end
  3. ViewController.m

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        ZYView *view = [[ZYView alloc] initWithFrame:CGRectMake(100, 100, 250, 250)];
        view.backgroundColor = [UIColor redColor];
        view.type = kDefaultPath;
        [view setNeedsDisplay];
        [self.view addSubview:view];
    }

三、CAShaplayer

  1. 说到CAShapLayer就不得不说到UIBezierPath: UIBezierPath是在 UIKit 中的一个类,继承于NSObject,可以创建基于矢量的路径。使用此类可以定义常见的圆形、多边形等形状 。我们使用直线、弧(arc)来创建复杂的曲线形状。每一个直线段或者曲线段的结束的地方是下一个的开始的地方。每一个连接的直线或者曲线段的集合成为subpath。一个UIBezierPath对象定义一个完整的路径包括一个或者多个subpaths
  2. CAShapeLayer: CAShapeLayer顾名思义,继承于CALayer。 每个CAShapeLayer对象都代表着将要被渲染到屏幕上的一个任意的形状(shape)。具体的形状由其path(类型为CGPathRef)属性指定。 普通的CALayer是矩形,所以需要frame属性。CAShapeLayer初始化时也需要指定frame值,但 它本身没有形状,它的形状来源于其属性path 。CAShapeLayer有不同于CALayer的属性,它从CALayer继承而来的属性在绘制时是不起作用的
  3. 步骤:
    1、新建UIBezierPath对象bezierPath
    2、新建CAShapeLayer对象caShapeLayer
    3、将bezierPath的CGPath赋值给caShapeLayer的path,即caShapeLayer.path = bezierPath.CGPath
    4、把caShapeLayer添加到某个显示该图形的layer中

四、综合实例

时间: 2024-10-13 09:09:55

长路漫漫,唯剑作伴--Core Animation的相关文章

长路漫漫,唯剑作伴--Core Animation优化

一.简介 当App发展到一定的规模,性能优化就成为必不可少的一点.但是很多人,又对性能优化很陌生,毕竟平常大多时间都在写业务逻辑,很少关注这个.最近在优化自己的项目,也收集了很多资料,这里先浅谈一下使用Instruments中CoreAnimation优化收获的经验以及总结,这是第一篇,后续会更新Timer Profiler,Leaks等其他优化工具的具体用法. 二.准备工作 在性能优化中一个最具参考价值的属性是FPS:全称Frames Per Second,其实就是屏幕刷新率,苹果的iphon

长路漫漫,唯剑作伴--小技巧

一.UIImageView添加圆角 第一种方法:通过设置layer的属性,但是最影响性能 UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)]; //只需要设置layer层的两个属性 //设置圆角 imageView.layer.cornerRadius = imageView.frame.size.width / 2; //将多余的部分切掉 imageView.lay

长路漫漫,唯剑作伴--基础

一.结构体 结构体定义 struct stu{ char *name; //姓名 int num; //学号 int age; //年龄 char group; //所在学习小组 float score; //成绩 } 结构体变量 struct stu stu1, stu2; struct stu{ char *name; //姓名 int num; //学号 int age; //年龄 char group; //所在学习小组 float score; //成绩 } stu1, stu2; s

长路漫漫,唯剑作伴--MVVM

开篇 MVC Model-View-Controller是一个用来组织代码的权威范式.Apple甚至是这么说的.在MVC下,所有的对象被归类为一个model,一个view,或一个controller.Model持有数据,View显示与用户交互的界面,而View Controller调解Model和View之间的交互. MVVM MVVM的出现主要是为了解决在开发过程中Controller越来越庞大的问题,变得难以维护,所以MVVM把数据加工的任务从Controller中解放了出来,使得Contr

长路漫漫,唯剑作伴--胡乱来一套

//第一种方法 NSDate *start = [NSDate date]; //2.根据url地址下载图片数据到本地(二进制数据) NSData *data = [NSData dataWithContentsOfURL:url]; NSDate *end = [NSDate date]; NSLog(@"第二步操作花费的时间为%f",[end timeIntervalSinceDate:start]); //第二种方法 CFTimeInterval start = CFAbsolu

长路漫漫,唯剑作伴--问题答案

一.使用atomic一定是线程安全的吗? 回答 不是 对于atomic的属性,系统生成的 getter/setter 会保证 get.set 操作的完整性,不受其他线程影响.比如,线程 A 的 getter 方法运行到一半,线程 B 调用了 setter:那么线程 A 的 getter 还是能得到一个完好无损的对象. 对于nonatomic的属性,当其中一个线程正在改写某属性值的时候,另外一个线程也许会突然闯入,把尚未修改好的属性值读取出来.发证这种情况时,线程读取到的属性值肯能不对. 当使用a

长路漫漫,唯剑作伴--loadView、viewDidLoad及viewDidUnload的关系

一.loadView 什么时候被调用? 每次访问UIViewController的view(比如controller.view.self.view)而且view为nil,loadView方法就会被调用. 有什么作用? loadView方法是用来负责创建UIViewController的view 默认实现是怎样的? 它会先去查找与UIViewController相关联的xib文件,通过加载xib文件来创建UIViewController的view 如果在初始化UIViewController指定了

长路漫漫,唯剑作伴--Automatic Reference Counting

一.简介 ARC,自动引用计数,是指iOS的内存管理使用引用计数的技术. 在OC中采用Automatic Reference Counting的机制,让编译器进行内存管理.在新一代的Apple LLVM编译器中设置ARC为有效状态,就不用再次键入retain.release代码,这在降低程序崩溃.内存泄漏等风险的同时,很大程度上减少了开发程序的工作量.编译器完全清楚目标对象,并能立刻释放那些不再被使用的对象(有待斟酌).如此一来,应用程序将具有可预测性,且运行流畅,速度也将大幅提升.(摘自苹果官

长路漫漫,唯剑作伴--Life Circle

一.load 和 initialize load 在load中使用其他类是不安全的,因为其它类不一定加载完毕: load方法不遵循继承规则,也就是说,如果某个类没有实现load方法,那么不管这个类的所有超类是否实现了这个方法,这个类都不会调用load 如果类和分类都实现了load方法,两个类都会执行load,类先执行,分类后执行: 实现了load方法的这个类,不管在程序运行中是否用到,程序在启动时都会把每个类中的load方法调用一次(这个和initialize不同). initialize 它是