美文网首页
CALayer之基础介绍

CALayer之基础介绍

作者: 春风依旧 | 来源:发表于2018-08-07 10:46 被阅读22次

    前言:

    在app开发中,我们经常会使用一些动画来增加应用的炫酷效果,从而达到吸引用户的目的。QuartzCore框架是做动画的基础,其实他就是CoreAnimation。这个框架的头文件只包含了CoreAnimation.h。

    UIView和CALayer

    相同点:
            1、同样是一些被层级关系树管理的矩形块;
            2、同样也可以包含图片、文字等内容,
            3、同样可用来做动画和变换,可以管理子图层等功能,
            4、平行层关系,做职责分离,避免许多重复的代码
    不同点:
            1、视图的职责就是创建并管理这个图层,以确保当子视图在层级关系中添加或者移除的时候,他们关联的图层也同样对应在层级关系树当中有相同的操作。
            2、CALayer不回去处理用户的交互事件。

    一、简单图层的使用

     // 创建简单的图层
        CALayer *layer = [CALayer layer];
        layer.frame = CGRectMake(100, 100, 200, 200);
        layer.backgroundColor = [UIColor redColor].CGColor;
        layer.contents = (id)[UIImage imageNamed:@"阿狸头像"].CGImage;
        [self.view.layer addSublayer:layer];
    

    二、CALayer的属性

    1、contents属性
       // 创建图层
        CALayer *layer = [CALayer layer];
        layer.frame = CGRectMake(100, 100, 200, 200);
        layer.position = self.view.center;
        layer.backgroundColor = [UIColor redColor].CGColor;
        // 设置图层内容
         layer.contents = (__bridge id)([UIImage imageNamed:@"狸头像"].CGImage);
        [self.view.layer addSublayer:layer];
    
    2、contentGravity属性
      // 创建图层
        CALayer *layer = [CALayer layer];
        layer.frame = CGRectMake(100, 100, 200, 200);
        layer.position = self.view.center;
        layer.backgroundColor = [UIColor redColor].CGColor;
        // 设置图层内容
        layer.contents = (__bridge id)([UIImage imageNamed:@"狸头像"].CGImage);
        // 设置填充模式
        layer.contentsGravity = kCAGravityResizeAspect;
        [self.view.layer addSublayer:layer];
    
    3、contentsScale属性
        // 创建图层
        CALayer *layer = [CALayer layer];
        layer.frame = CGRectMake(100, 100, 200, 200);
        layer.position = self.view.center;
        layer.backgroundColor = [UIColor redColor].CGColor;
        // 设置图层内容
        layer.contents = (__bridge id)([UIImage imageNamed:@"狸头像"].CGImage);
        // 设置填充模式
        layer.contentsGravity = kCAGravityCenter;
        // 设置 contentsScale
        layer.contentsScale = 2;  // 一般设置为 [UIScreen mainScreen].scale,可根据设备自动调整
        // 将其放大,让其模糊来演示contentsScale
        layer.transform = CATransform3DMakeScale(3, 3, 0);
        //添加到视图关联的图层上
        [self.view.layer addSublayer:layer];
    
    4、contentsRect属性:裁剪的效果,范围是 {0, 0, 1, 1}
        // 创建图层
        CALayer *layer = [CALayer layer];
        layer.frame = CGRectMake(0, 0, 200, 200);
        layer.position = self.view.center;
        layer.backgroundColor = [UIColor redColor].CGColor;
        // 设置图层内容
        layer.contents = (__bridge id)([UIImage imageNamed:@"阿狸头像"].CGImage);
        // 设置 contentsRect
        layer.contentsRect = CGRectMake(0, 0, 0.5, 0.5);
        //添加到视图关联的图层上
        [self.view.layer addSublayer:layer];
    
    5、contentsCenter:将图片进行局部拉伸,contentsCenter 是一个 CGRect,它定义了一个固定的边框和一个在图层上可拉伸的区域。默认情况下,contentsCenter 的拉伸区域是{0, 0, 1, 1}``
    6、绘制图形

            在 UIView 中,我们可以重写 drawRect: 来绘制图形(开发者可以调用setNeedsDisplay方法触发)。实质上该方法封装了 CALayer 的绘制方法。

    -(void)drawRectWithLayer{  
        // 创建子图层
        CALayer* subLayer = [CALayer new];
        // 布局
        subLayer.frame = CGRectMake(0, 0, 150, 150);
        subLayer.position = self.view.center;
        // 设置颜色
        subLayer.backgroundColor = UIColor.groupTableViewBackgroundColor.CGColor;
        // 设置代理
        subLayer.delegate = self;
        // 添加到视图关联图层上
        [self.view.layer addSublayer:subLayer];
        // 触发 CALayer 的绘制
        [subLayer display];
    
    /*
     -display 触发代理方法
       1、- (void)displayLayer:(CALayerCALayer *)layer;
       2、- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
     */
    }
    
    // 完成绘制的代理方法
    -(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
        CGContextSetLineWidth(ctx, 10.0f);
        CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
        CGContextStrokeEllipseInRect(ctx, layer.bounds);
    }
    

    三、CALayer的几何相关

    1、布局
    frame,bounds 和 position(中心的意思)
    2、锚点
    anchorPoint :对于整个图形来表示是(1,1),某个点在这个图形的位置比例。
    3、坐标系

    //不同坐标系之间的图层转换提供了一些工具类方法
    - (CGPoint)convertPoint:(CGPoint)point fromLayer:(CALayer *)layer;
    - (CGPoint)convertPoint:(CGPoint)point toLayer:(CALayer *)layer;
    - (CGRect)convertRect:(CGRect)rect fromLayer:(CALayer *)layer;
    - (CGRect)convertRect:(CGRect)rect toLayer:(CALayer *)layer;
    
    //调整视图的层级关系
    - (void)insertSublayer:(CALayer *)layer atIndex:(unsigned)idx;
    - (void)insertSublayer:(CALayer *)layer below:(nullable CALayer *)sibling;
    - (void)insertSublayer:(CALayer *)layer above:(nullable CALayer *)sibling;
    
    

    4、Hit Testing -- 两种方法

      
        CGPoint point = [[touches anyObject] locationInView:self.view];
        // 将落点转换到红色背景的图层的层级上,以判断是否被包含
        point = [self.subLayer convertPoint:point fromLayer:self.view.layer];
        
    #pragma mark - 判断一个点是否在图层的 frame 范围内,如果在就返回 YES,反之为 NO
        if ([self.subLayer containsPoint:point]) {
            [[[UIAlertView alloc] initWithTitle:@"在红色图层中"
                                        message:nil
                                       delegate:nil
                              cancelButtonTitle:@"OK"
                              otherButtonTitles:nil] show];
        }
        else{
            [[[UIAlertView alloc] initWithTitle:@"未在红色图层中"
                                        message:nil
                                       delegate:nil
                              cancelButtonTitle:@"OK"
                              otherButtonTitles:nil] show];
        }
     
    #pragma mark - 接受一个点,但是它返回的是包含这个点的图层
    //    CALayer *layer = [self.view.layer hitTest:point];
    //    if (layer == self.subLayer) {
    //        [[[UIAlertView alloc] initWithTitle:@"在红色图层中"
    //                                    message:nil
    //                                   delegate:nil
    //                          cancelButtonTitle:@"OK"
    //                          otherButtonTitles:nil] show];
    //    }else{
    //
    //        [[[UIAlertView alloc] initWithTitle:@"未在红色图层中"
    //                                    message:nil
    //                                   delegate:nil
    //                          cancelButtonTitle:@"OK"
    //                          otherButtonTitles:nil] show];
    //    }
        
    

    四、CALayer的特殊效果

    1、maskToBounds
             maskToBounds 可以切除超出图层的部分,UIView中类似的有 clipsToBounds。
    2、 borderWidth(边宽) 和 borderColor(边颜色)
    3、阴影

    /*
         shadowOpacity 控制图层阴影的透明度
         shadowColor 阴影的颜色
         shadowOffset 阴影的方向和距离
         shadowRadius 阴影的的模糊度
         注意:
            阴影效果不能使用masksToBounds,如若使用阴影效果会消失
         */
        
        CALayer *layer = [CALayer new];
        layer.frame = CGRectMake(50, 100, 150, 150);
        layer.position = self.view.layer.position;
        layer.backgroundColor = UIColor.redColor.CGColor;
        // 先 添加到视图关联图层上
        [self.view.layer addSublayer:layer];
        
        // 阴影层做阴影部分的设置
        layer.cornerRadius = 10;
        layer.shadowOpacity = 1;
        layer.shadowColor = UIColor.brownColor.CGColor;
        layer.shadowOffset = CGSizeMake(0, -3); //默认值
        layer.shadowRadius = 10;
    

    五、mask蒙版/遮罩

            蒙版/遮罩解决了展现的内容是一个不规则的形状,CALayer 有一个属性 mask,这个属性本身就是一个 CALayer 类型,它的内容轮廓定义了父图层的可见部分,其他部分则会被抛弃。如下图:

    mask遮罩.png
    @interface LayerMaskController ()
    
    @property (strong, nonatomic)CALayer* maskLayer1;
    @property (strong, nonatomic)CAShapeLayer* maskLayer2;
    
    @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    @property (weak, nonatomic) IBOutlet UIImageView *imageView1;
    @property (weak, nonatomic) IBOutlet UIImageView *imageView2;
    
    @end
    
    @implementation LayerMaskController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.imageView1.layer.mask = self.maskLayer1;
        self.imageView2.layer.mask = self.maskLayer2;
        
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
        animation.duration = 1.0f;
        animation.toValue = @(M_PI);
        animation.autoreverses = YES;
        animation.repeatCount = HUGE_VALF; //无穷大,循环
        [self.maskLayer1 addAnimation:animation forKey:@"animation"];
        [self.maskLayer2 addAnimation:animation forKey:@"animation"];
        
    }
    
    // 寄宿图为图片
    -(CALayer *)maskLayer1{
        if (_maskLayer1==nil) {
            _maskLayer1 = [CALayer new];
            _maskLayer1.frame = self.imageView.bounds;
            UIImage* image = [UIImage imageNamed:@"clip"];
            _maskLayer1.contents = (__bridge id)image.CGImage;
        }
        return _maskLayer1;
    }
    
    // 寄宿图为自定义图形
    -(CAShapeLayer *)maskLayer2{
        if (_maskLayer2==nil) {
            _maskLayer2 = [CAShapeLayer new];
            _maskLayer2.frame = self.imageView.bounds;
            UIBezierPath* path = [UIBezierPath bezierPathWithOvalInRect:_maskLayer1.bounds];
            _maskLayer2.path = path.CGPath;
        }
        return _maskLayer2;
    }
    

    六、图层的变换

            CALayer 做二维空间变换的属性叫做 affineTransform,而其属性 transform 是一个 CATransform3D 类型,可以将图层在三维空间变换效果。

    相关文章

      网友评论

          本文标题:CALayer之基础介绍

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