zoukankan      html  css  js  c++  java
  • iOS_核心动画CALayer(一)

    目  录:
    一、核心动画简介
    二、图层与视图之间的关系
    三、CALayer的使用说明
    四、CALayer的隐式动画属性
    五、在CALayer上绘图
    六、总结
     
     
    一、核心动画简介
      Core Animation 是跨平台的,支持iOS环境和Mac OS X环境,而CALayer是核心动画的基础,可以帮助开发者做圆角、阴影、边框等效果。我们学习核心动画之前,需要先理解CALayer,因为核心动画操作的对象不是UIView,而是CALayer。对于UIView控件每个内部都有一个Layer的属性。我们在实现核心动画时,本质上是将CALayer中的内容转换成位图,从而便于图形硬件的操纵。
    二、图层和视图之间的关系

      创建视图对象时,视图会自己创建一个层,视图在绘图(如drawRect:)时,会将内容画在自己的层上。当视图在层上完成绘图后,系统会将图层拷贝至屏幕。每个视图都有一个层,而每个图层又可以有多个子层。

      提示:

      1.Layer的设计目的不是为了取代视图,因此不能基于CALayer创建一个独立的可视化组件

      2.Layer的设计目的是提供视图的基本可视内容,从而提高动画的执行效率

      3.除提供可视内容外,Layer不负责视图的事件响应、内容绘制等工作,同时Layer不能参与到响应者链条中

    三、CALayer的使用说明

    • 通过UIView的layer属性可以拿到对应的根层,这个层不允许重新创建,但可以往层里面添加子层(调用CALayer的addSublayer)
    • 要具体使用CALayer,需要引入<QuartzCore/QuartzCore.h>
    • 获取当前图层或使用静态方法layer初始化CALayer后,可以设置以下属性:
    1. bounds:宽度和高度
    2. position:位置(默认指中心点,具体由anchorPoint决定)
    3. anchorPoint:锚点(x,y的范围都是0-1),决定了position的含义
    4. backgroundColor: 背景颜色(CGColorRef类型)
    5. borderColor:边框颜色(CGColorRef类型)
    6. borderWidth:边框宽度
    7. cornerRadius:圆角半径
    8. contents: 内容(比如设置为图片CGImageRef)
    • 注意:虽然CALayer可以使用frame,但最好还是使用bounds和position。为层设置动画时,用bounds和position会方便一点。

      下面通过一个案例,来学会运用CALayer的常用属性:

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.view.backgroundColor = [UIColor grayColor];
        //设置UIView上CALayer的圆角半径
        self.view.layer.cornerRadius = 8;
        self.view.layer.borderWidth = 4;
        self.view.layer.borderColor = [[UIColor redColor]CGColor];
        
        //创建子层
        CALayer *subLayer = [CALayer layer];
        subLayer.backgroundColor = [[UIColor  magentaColor]CGColor];
        //设置圆角半径
        subLayer.cornerRadius = 8;
        subLayer.borderWidth = 2;
        subLayer.borderColor = [[UIColor blackColor]CGColor];
        //阴影的偏移
        subLayer.shadowOffset = CGSizeMake(4, 5);
        //设置subLayer的阴影的模糊程度
        subLayer.shadowRadius = 1;
        subLayer.shadowColor = [[UIColor blackColor]CGColor];
        //设置阴影的透明度
        subLayer.shadowOpacity = 0.8;
        subLayer.frame = CGRectMake(30, 30, 120, 160);
        [self.view.layer addSublayer:subLayer];
        
        
        CALayer *subLayer2 = [CALayer layer];
        subLayer2.cornerRadius = 8;
        subLayer2.borderWidth = 2;
        subLayer2.borderColor = [[UIColor blackColor]CGColor];
        subLayer2.shadowOffset = CGSizeMake(4, 5);
        subLayer2.shadowRadius = 1;
        subLayer2.shadowColor = [[UIColor blackColor]CGColor];
        subLayer2.shadowOpacity = 0.8;
        subLayer2.frame = CGRectMake(170, 30, 120, 160);
        [self.view.layer addSublayer:subLayer2];
        
        CALayer *imageLayer = [CALayer layer];
        //imageLayer层显示的内容
        imageLayer.contents = (id)[UIImage imageNamed:@"5.jpg"];
        imageLayer.frame = subLayer2.bounds;
        [subLayer2 addSublayer:imageLayer];
        
        
        CALayer *customDrawn = [CALayer layer];
        customDrawn.delegate = self;
        customDrawn.backgroundColor = [[UIColor greenColor]CGColor];
        customDrawn.frame = CGRectMake(30, 220, 260, 210);
        customDrawn.shadowOffset = CGSizeMake(0, 3);
        customDrawn.shadowRadius = 5.0;
        customDrawn.shadowColor = [[UIColor blackColor]CGColor];
        customDrawn.shadowOpacity = 0.8;
        customDrawn.cornerRadius = 10.0;
        customDrawn.borderColor = [[UIColor blackColor]CGColor];
        customDrawn.borderWidth = 2.0;
        
        customDrawn.masksToBounds = YES;
        [self.view.layer addSublayer:customDrawn];
        [customDrawn setNeedsDisplay];
    }
    -(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
    {
        UIColor *bgColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"6.jpg"]];
        CGContextSetFillColorWithColor(ctx, [bgColor CGColor]);
        CGContextFillEllipseInRect(ctx, CGRectMake(20, 30, 100, 100));
        CGContextFillPath(ctx);
        CGContextSetRGBStrokeColor(ctx, 1, 1, 0, 1);
        CGContextStrokePath(ctx);
    
    }
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end

      运行结果如下图:

    四、CALayer的隐式动画属性

    • 每一个UIView内部都默认关联着一个CALayer,称这个Layer为Root Layer。所有的非Root Layer都存在着隐式动画,隐式动画的默认时长为1/4秒。 
    • 当修改非Root Layer的部分属性时,相应的修改会自动产生动画效果,能执行隐式动画的属性被称为“可动画属性”,诸如:
    1. bounds: 缩放动画
    2. position: 平移动画
    3. opacity: 淡入淡出动画(改变透明度)
    • 在文档中搜素animatable可以找到所有可动画属性
    • 如果要关闭默认的动画效果,可以通过动画事务方法实现:

      [CATransaction begin];//开启事务

      [CATransaction setDisableActions:YES];//取消隐式动画

      [CATransaction commit];//事务提交
    #import "ViewController.h"
    
    @interface ViewController ()
    @property(strong,nonatomic)CALayer *layer;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // 创建子层
       self.layer = [[CALayer alloc]init];
        //设置子层的bounds
        _layer.bounds = CGRectMake(0, 0, 100, 100);
        //设置背景颜色
        _layer.backgroundColor = [[UIColor blueColor]CGColor];
        //设置位置
        _layer.position = CGPointMake(100, 100);
        
        [self.view.layer addSublayer:_layer];
    }
    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        //事务开始
        [CATransaction begin];
    //    //取消隐式动画
    //    [CATransaction setDisableActions:YES];
        //设置隐式动画的时长(如果取消隐式动画,则不起作用)
        [CATransaction setAnimationDuration:1.0];
        
        UITouch *touch = [touches anyObject];
        CGPoint location = [touch locationInView:self.view];
        _layer.position = location;
        //视图提交
        [CATransaction commit];
        
    }
    
    @end

    五、在CALayer上绘图

      要在CALayer上绘图,有两种方法:

      (1)创建一个CALayer的子类,然后覆盖drawInContext:方法,可以使用Quartz2D API在其中进行绘图

      (2)设置CALayer的delegate,然后让delegate实现drawLayer:inContext:方法进行绘图

      注意:

      (1)不能再将UIView设置为这个CALayer的delegate,因为UIView对象已经是内部层的delegate,再次设置会出问题

      (2)无论使用哪种方法,都必须向层发送setNeedsDisplay消息,以触发相应绘图方法的调用

       第一种:使用子类
      首先创建一个继承于CALayer的MyLayer类,覆盖drawInContext:方法
    #import "MyLayer.h"
    
    @implementation MyLayer
    -(void)drawInContext:(CGContextRef)ctx
    {
        CGContextAddRect(ctx, CGRectMake(0, 0, 50, 50));
        CGContextSetRGBFillColor(ctx, 0, 1, 1, 1);
        CGContextDrawPath(ctx, kCGPathFillStroke);
    }
    @end

      再看下实现文件的代码:

    #import "ViewController.h"
    #import "MyLayer.h"
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // 创建子层
        MyLayer *subLayer = [[MyLayer alloc]init];
        //设置子层的背景颜色
        subLayer.backgroundColor = [[UIColor redColor]CGColor];
        //设置子层bounds
        subLayer.bounds = CGRectMake(0, 0, 100, 100);
        //设置子层的位置
        subLayer.position = CGPointMake(100, 100);
        //将子层添加到view层中
        [self.view.layer addSublayer:subLayer];
        //当重绘的时候会调用此方法
        [subLayer setNeedsDisplay];
    }
    
    @end

      第二种:使用代理

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // 创建子层
        CALayer *subLayer = [[CALayer alloc]init];
        //设置bounds;
        subLayer.bounds = CGRectMake(0, 0, 100, 100);
        //设置位置
        subLayer.position = CGPointMake(100, 100);
        //设置锚点
        subLayer.anchorPoint = CGPointMake(0.5, 0.5);
        //设置背景色
        subLayer.backgroundColor = [[UIColor blueColor]CGColor];
        
        //将创建的子层,添加到view的子层中
        [self.view.layer addSublayer:subLayer];
        //设置代理
        subLayer.delegate = self;
        //重绘时调用此方法
        [subLayer setNeedsDisplay];
        
    }
    #pragma mark - CALayer的代理方法
    -(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
    {
        //绘制图形
        CGContextAddRect(ctx, CGRectMake(0, 0, 50, 50));
        //设置图形的填充颜色
        CGContextSetRGBFillColor(ctx, 0, 1, 0, 1);
        CGContextDrawPath(ctx, kCGPathFillStroke);
        
        //绘制图片
        UIImage *image = [UIImage imageNamed:@"1.png"];
        //旋转图片
        CGContextScaleCTM(ctx, 1, -1);
        CGContextTranslateCTM(ctx, 0,-100);
        //绘制图片
        CGContextDrawImage(ctx, CGRectMake(0, 0, 100, 100),[image CGImage]);
        
    }
    @end

    六、总结

      1.CALayer、UIView以及上下文的之间的关系

      (1)当UIView收到setNeedsDisplay消息时,CALayer会准备好一个CGContextRef,然后向它的delegate即UIView发送消息,并且传入已经准备好的CGContextRef对象。UIView在drawLayer:inContext:方法中会调用自己的drarRect:方法。

      (2)平时在drawRect:中通过UIGraphicsGetCurrentContext()获取的就是有CALayer传入的CGContextRef对象,在drawRect:中完成的所有绘图都会填入CALayer的CGContextRef中,然后被拷贝至屏幕

      (3)CALayer的CGContextRef用的是位图上下文(Bitmap Grahpics Context)。

  • 相关阅读:
    WPF换肤之八:创建3D浏览效果
    ADPlus
    由INotifyPropertyChanged,BindingList绑定引发的跨线程异常及其解决办法
    无服务器端的UDP群聊功能剖析(重构版本)
    A Short Guide to DBI[转]
    绑定到异步的ObservableCollection
    使用反射+缓存+委托,实现一个不同对象之间同名同类型属性值的快速拷贝
    ORM查询语言(OQL)简介概念篇
    无需重新编译代码,在线修改表单
    LJMM平台( Linux +Jexus+MySQL+mono) 上使用MySQL的简单总结
  • 原文地址:https://www.cnblogs.com/xjf125/p/4878862.html
Copyright © 2011-2022 走看看