iOS中的CALayer

作者: 七号萝卜 | 来源:发表于2016-11-02 08:43 被阅读211次

    找工作过程中,iOS动画貌似问的有点多。恰巧过去并没有好好学过iOS中的动画,因此想在这里记录一下,也方便以后查看。这篇先来记录与动画有关系的CALayer。

    关于CALayer的文章,网上已经有很多了。因此也是拾人牙慧了。

    iOS中的视图,我们一般用UIView来绘制。而UIView之所以能够显示到屏幕上供我们看见,就是因为UIView里面包含了一层CALayer,它才是真正进行绘制的图层。当UIView需要显示到屏幕上时,会调用drawRect:方法进行绘图,并且会将所有内容绘制在自己的层上,绘图完毕后,系统会将层拷贝到屏幕上,于是就完成了UIView的显示。

    因此我们操纵calayer,就能改变UIView的显示效果。

    那么UIView和CALayer有什么区别呢?UIView负责绘制的也是CALayer,它主要是接受一些事件的响应,CALayer就负责纯画图。

    CALayer是被定义在QuartzCore框架中的,看网上的老教程都是说要先导入QuartzCore框架,不过现在新建的工程里已经导入了,所以能直接在工程里用了。只需引入相应的头文件。

    #import <QuartzCore/QuartzCore.h>
    

    每一个UIView就包含了一个layer,这个可以称为根layer,我们也可以自己新建layer,然后和加子view一样作为子layer加到根layer上。操作方法和加view一样一样的,只是方法名不同罢了。

    [self.view.layer addSublayer:mylayer];
    

    新建图层的方法:

    CALayer *myLayer = [CALayer layer];
    myLayer.bounds = CGRectMake(0, 0, 100, 100);
    myLayer.position = CGPointMake(100, 100);
    myLayer.backgroundColor = [UIColor redColor].CGColor;
    myLayer.cornerRadius = 10;[self.view.layer addSublayer:myLayer];
    

    其中bounds,position,backgroundColor,cornerRadius那些是CALayer的属性。

    bounds:用于设置CALayer的宽度和高度。修改这个属性会产生缩放动画;
    backgroundColor:用于设置CALayer的背景色。修改这个属性会产生背景色的渐变动画;
    position:用于设置CALayer的位置。修改这个属性会产生平移动画;
    anchorPoint:所说的锚点,决定着CALayer身上的哪个点会在position属性所指的位置。取值范围都是0~1,默认值为(0.5, 0.5);
    cornerRadius:设置圆角;

    以上是些常用的一些属性。

    另外,如果是图层中需要显示图片,不能直接用UIImage:

    myLayer.contents = (id)[UIImage imageNamed:@"demo.png"].CGImage;
    //如加了图片,又要设置圆角,需要将masksToBounds设置成YES,才有效果
    myLayer.cornerRadius = 10;
    myLayer.masksToBounds = YES;
    

    这里设置的图片是CGImageRef类型的数据,通过UIImage的CGImage属性能够转换。同样层中也不能用UIColor,需将UIColor转换为CGColorRef类型,用UIColor的CGColor属性。

    为什么会这样呢?原因在于CALayer是定义在QuartzCore框架中的;CGImageRef、CGColorRef两种数据类型是定义在CoreGraphics框架中的;UIColor、UIImage是定义在UIKit框架中的。而QuartzCore框架和CoreGraphics框架是可以跨平台使用的,在iOS和Mac OS X上都能使用,但是UIKit只能在iOS中使用。因此,为了保证可移植性,QuartzCore不能使用UIImage、UIColor,只能使用CGImageRef、CGColorRef。

    还有个就是选择UIView和CALayer的问题。因为UIView就比CALayer多了个事件处理功能,因此需要交互的话,就用UIView;只需要绘图的话,就用CALayer了,这样效率要高些了。

    再来说说自定义CALayer的事。自定义层就是在层上绘图,有两种方法。

    第一种可以通过创建一个CALayer的子类,然后覆盖drawInContext:方法,使用Quartz2D API进行绘图。仿照网上教程的一个例子:

    @implementation MyLayer
    
    #pragma mark 绘制一个实心三角形
    - (void)drawInContext:(CGContextRef)ctx {
       // 设置为蓝色 
       CGContextSetRGBFillColor(ctx, 0, 0, 1, 1);
       // 设置起点
       CGContextMoveToPoint(ctx, 50, 0); 
       // 从(50, 0)连线到(0, 100)
       CGContextAddLineToPoint(ctx, 0, 100);
       // 从(0, 100)连线到(100, 100)
       CGContextAddLineToPoint(ctx, 100, 100);
       // 合并路径,连接起点和终点
       CGContextClosePath(ctx);
    
      // 绘制路径
      CGContextFillPath(ctx);
    }
    @end
    

    在需要用到的地方添加:

    MyLayer *layer = [MyLayer layer];
    layer.bounds = CGRectMake(0, 0, 100, 100);
    layer.position = CGPointMake(100, 100);
    
    // 开始绘制图层
    [layer setNeedsDisplay];
    [self.view.layer addSublayer:layer];
    

    绘制图层需要调用setNeedsDisplay方法,它会自动触发drawInContext方法的调用,进行绘图。

    第二种方法是设置CALayer的delegate,然后让delegate实现drawLayer:inContext:方法,当CALayer需要绘图时,会调用delegate的drawLayer:inContext:方法进行绘图。不过不能将某个UIView设置为CALayer的delegate,因为UIView对象已经是它内部根层的delegate,再次设置为其他层的delegate会出问题。

    CALayer *layer = [CALayer layer];
    // 设置delegate
    layer.delegate = self;
    layer.bounds = CGRectMake(0, 0, 100, 100);
    layer.position = CGPointMake(100, 100);
    // 开始绘制图层
    [layer setNeedsDisplay];
    [self.view.layer addSublayer:layer];
    

    还是需要setNeedsDisplay来通知delegate进行绘制。

    - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
      CGContextSetRGBStrokeColor(ctx, 0, 0, 1, 1);              
      CGContextSetLineWidth(ctx, 10);
      // 添加一个跟层一样大的矩形到路径中 
      CGContextAddRect(ctx, layer.bounds);
      // 绘制路径 
      CGContextStrokePath(ctx);
    

    这个delegate是写在Controller中的。

    另外还有个CAReplicatorLayer比较常用,它可以让其子类具有相同的属性。
    附上一篇写的好的文章:http://www.jianshu.com/p/b660eb8b8bc1

    最后,为什么要调用setNeedsDisplay而不直接用drawInContext?以及有次笔试题遇到的问setNeedsLayout和layoutIfNeeded各自作用是什么?有什么区别?下次再记录。

    相关文章

      网友评论

        本文标题:iOS中的CALayer

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