CALayer
寄宿图
view.layer.contents = (__bridge id)image.CGImage;// contentsGravity 设置图片的位置view.layer.contentsGravity = kCAGravityResizeAspect;// contenstsScale 属性定义了寄宿图的像素尺寸和视图大小的比例view.layer.contenstsScale = image.scale;// 图片拼图view.layer.contentsRect = CGRectMake(0,0.5,0.5,0.5);复制代码
布局
frame 代表图层的外部坐标。
bounds 代表图层的内部坐标。
center是UIView的中心点。position是layer的中心点。
锚点
anchorPoint 是移动图层的把柄。
经典案例 中标的时针、分针、秒针。
z坐标系
zPosition = 1.0f;
可以用来调整图层现实的顺序。
Hit Testing
zPosition属性不会改变图层树中的顺序。不能改变事件传递的顺序。
CALayer *layer = [self.layerView.layer hitTest:point];if(layer == self.someLayer){ ........}复制代码
视觉效果
圆角
layer.cornerRadius = 20.0f;复制代码
图层边框
layer.borderWidth = 5.0f;layer.borderColor = [UIColor redColor].CGColor;复制代码
阴影
layer.shadowOpacity = 0.5f;layer.shadowColor = [UIColor redColor].CGColor;layer.shadowOffset = CGSize; // 阴影的方向和距离layer.shadowRadius = 5; 阴影模糊度复制代码
shadowPath属性
实时计算阴影消耗性能,使用shadowPath可以提高性能。
CGMutablePathRef squarePath = CGPathCreateMutable();CFPathAddRect(squarePath,NULL,self.layerView.bounds);layerView.layer.shadowPath = squarePath;CGPathRelease(squarePath);复制代码
复杂图形使用UIBezierPath
图层蒙版
CALayer * layer = [CALayer layer];CALayer * maskLayer = [CALayer layer];layer.mask = maskLayer;复制代码
使用透明图片作为蒙版
- (void)viewDidLoad { [super viewDidLoad]; CALayer * layer = [CALayer layer]; layer.frame = CGRectMake(80, 80, 300, 300); // 直接设置layer的contents属性,它可以是一张图片的内容,但是我们的layer同样不认识UIKit下面的UIImage,它只接收CGImageRef,所以使用桥接来进行强转 layer.contents = (__bridge id)[UIImage imageNamed:@"content.png"].CGImage; [self.view.layer addSublayer:layer]; CALayer * maskLayer = [CALayer layer]; // 蒙版的坐标是基于它所影响的那个图层的坐标系 maskLayer.frame = CGRectMake(0, 0, 300, 300); maskLayer.contents = (__bridge id)[UIImage imageNamed:@"mask.png"].CGImage; // 将maskLayer作为layer的蒙版 layer.mask = maskLayer;}复制代码
使用CAShapeLayer 来绘制蒙版
- (void)viewDidLoad { [super viewDidLoad]; CALayer * layer = [CALayer layer]; layer.frame = CGRectMake(80, 80, 300, 300); // 直接设置layer的contents属性,它可以是一张图片的内容,但是我们的layer同样不认识UIKit下面的UIImage,它只接收CGImageRef,所以使用桥接来进行强转 layer.contents = (__bridge id)[UIImage imageNamed:@"content.png"].CGImage; [self.view.layer addSublayer:layer]; UIBezierPath * bezierPath = [UIBezierPath bezierPath]; // 起始点在(图片宽的一半,0)的位置 [bezierPath moveToPoint:CGPointMake(150, 0)]; // 大概估算一下x和y的值 [bezierPath addLineToPoint:CGPointMake(40, 150)]; // 向右拉一条二阶贝塞尔曲线,控制点在中部偏下 [bezierPath addQuadCurveToPoint:CGPointMake(260, 150) controlPoint:CGPointMake(150, 300)]; // 闭合曲线,这样就会从当前点(150,300)到起始点(150,0)连线来进行闭合 [bezierPath closePath]; // 构造蒙版图层 CAShapeLayer * maskLayer = [CAShapeLayer layer]; maskLayer.path = bezierPath.CGPath; // 因为maskLayer的填充颜色默认是存在的,所以可以直接作为蒙版 layer.mask = maskLayer;}复制代码
给蒙版添加动画
CABasicAnimation * animation = [CABasicAnimation animation]; animation.keyPath = @"strokeEnd"; animation.duration = 3; animation.fromValue = @0; // 由于maskLayer默认的strokeEnd就是1,所以这里不再需要重新设置modelLayer的属性 [maskLayer addAnimation:animation forKey:nil];复制代码
变换
仿射变换
创建CGAffineTransform
CGAffineTransformMakeRation(CGFloat angle);CGAffineTransformMakeScale(CGFloat sx, CGFloat sy);CGAffineTransformMaleTranslation(CGFloat tx, CGFloat ty);复制代码
混合变换
初始生成一个单位矩阵
//创建CGAffineTransform的对象CGAffineTransform transform = CGAffineTransformIdentity;//设置 处理对象缩小50%transform = CGAffineTransformScale(transform, 0.5, 0.5);//设置 处理对象旋转30度角transform = CGAffineTransformRotate(transform, M_PI / 180.0 * 30);//接着 偏移200像素transform = CGAffineTransformTranslate(transform, 200, 0);//对需要处理的对象赋值:affineTransformself.imageView.layer.affineTransform = transform;复制代码
变换的顺序会影响最终的结果复制代码
3D变换
Core Animation提供一些方法用来创建和组合CATransform3D类型的矩阵,只不过函数的参数多了一个z参数,这些函数的返回值是CATransform3D类型的
CATransform3DMakeTranslation (CGFloat tx, CGFloat ty, CGFloat tz)CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz)CATransform3DMakeRotation (CGFloat angle, CGFloat x, CGFloat y, CGFloat z) 复制代码
基于一个CATransform3D进行的再次变换,也就是组合复杂的变换
CATransform3DTranslate (CATransform3D t, CGFloat tx, CGFloat ty, CGFloat tz)CATransform3DScale (CATransform3D t, CGFloat sx, CGFloat sy, CGFloat sz)CATransform3DRotate (CATransform3D t, CGFloat angle, CGFloat x, CGFloat y, CGFloat z)复制代码
结合两个变换
CATransform3D CATransform3DConcat (CATransform3D a, CATransform3D b)复制代码
透视投影
CATransform3D的透视效果是通过一个矩阵中的m34元素来控制的,所以要想有透视效果,可以手动修改矩阵中的m34的值,一般将值设为-1.0/d,d代表视角相机和屏幕间的距离,自己设定就好,一般d在500~1000之间。
//创建单位矩阵 CATransform3D transform = CATransform3DIdentity; //应用透视perspective,改变单位矩阵的m34的值 transform.m34 = -1.0/50.0; //顺着Y轴旋转45度 transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0); view.layer.transform = transform 复制代码
灭点
在透视绘图中,当物体远离到极限时,就变成一个点,于是所有的物体最后都会聚到一个点,通常这个点是视图的中心。所以在应用中灭点应该是屏幕中心或是包含所有3D对象的视图中点
Core Animation将灭点定在变换图层的anchorPoint,当改变图层的position时,也就改变了他的灭点。所以一定要谨记,在改变m34产生3D效果时,一定先将它放置到屏幕中央,然后通过平移将它一到指定位置(而不是直接改变它的position),这样所有的3D图层都共享一个灭点。
sublayerTransform 属性
CALayer的属性sublayerTransform,是CATransform3D类型,他影响所有的子图层,好处是一次性对设置包含这些图层的容器做变换,于是所有的子图层都自动继承这个变换方法
//设置容器view UIView *view = [[UIView alloc]initWithFrame:CGRectMake(10, 150, kGetViewWidth(self.view)-20, 400)]; [self.view addSubview:view]; //设置view1 UIView *view1 = [[UIView alloc]initWithFrame:CGRectMake(5, 10, kGetViewWidth(self.view)/2-20, 380)]; [view addSubview:view1]; UIImage *image = [UIImage imageNamed:@"1.jpg"]; view1.layer.contents = (__bridge id)image.CGImage; //设置view2 UIView *view2 = [[UIView alloc]initWithFrame:CGRectMake(kGetViewWidth(self.view)/2+5, 10, kGetViewWidth(self.view)/2-30, 380)]; [view addSubview:view2]; UIImage *image1 = [UIImage imageNamed:@"1.jpg"]; view2.layer.contents = (__bridge id)image1.CGImage; //对父图层即图层容器应用perspective CATransform3D transform = CATransform3DIdentity; //改变transform的m34的值 transform.m34 = -1.0/250.0; view.layer.sublayerTransform = transform; //对view1沿y轴旋转45度 CATransform3D transform1 = CATransform3DMakeRotation(M_PI_4, 0, 1, 0); view1.layer.transform = transform1; //对view2沿y轴旋转45度 CATransform3D transform2 = CATransform3DMakeRotation(-M_PI_4, 0, 1, 0); view2.layer.transform = transform2;复制代码
背面
将角度该为M_PI,就可以看到图层背面,而且可以通过CALayer的doubleSided
属性可以设置图层背面是否要被绘制 扁平化图层
每个图层的3D场景其实是扁平化的,当你从正面观察一个图层,看到的实际上由子图层创建的想象出来的3D场景,但当你倾斜这个图层,你会发现实际上这个3D场景仅仅是被绘制在图层的表面
专用图层
UIBezierPath
//初始化+ (instancetype)bezierPath;//矩形+ (instancetype)bezierPathWithRect:(CGRect)rect;//在rect所表示的矩形中画椭圆形+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect;//圆角矩形,rect:矩形位置、形状。cornerRadius:定点的圆角半径+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius;+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;*画圆,一个实例方法,一个类方法。*center:圆心位置*radius:半径*startAngle:开始的点*endAngle:结束的点*clockwise:是否顺时针画+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;//于CGPathRef结合绘制路径+ (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;@property(nonatomic) CGPathRef CGPath;//将UIBezierPath类转化成CGPathRef- (CGPathRef)CGPath//绘制起点- (void)moveToPoint:(CGPoint)point;//绘制除起点外的其它点- (void)addLineToPoint:(CGPoint)point;*绘制曲线(起点由moveToPoint:绘制)*endPoint:终点*controlPoint1:第一个控制点*controlPoint2:第二个控制点- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;//绘制曲线(只有一个控制点)- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;//闭合路径,即在终点和起点连一根线- (void)closePath;//移除所有点- (void)removeAllPoints;//在原有基础上连接路径- (void)appendPath:(UIBezierPath *)bezierPath;//扭转路径,即起点变成终点,终点变成起点- (UIBezierPath *)bezierPathByReversingPath;//路径进行仿射变换- (void)applyTransform:(CGAffineTransform)transform;// Path info@property(readonly,getter=isEmpty) BOOL empty;@property(nonatomic,readonly) CGRect bounds;@property(nonatomic,readonly) CGPoint currentPoint;- (BOOL)containsPoint:(CGPoint)point;//线宽、线端点类型、线连接类型、线拐角处宽度@property(nonatomic) CGFloat lineWidth;@property(nonatomic) CGLineCap lineCapStyle;@property(nonatomic) CGLineJoin lineJoinStyle;@property(nonatomic) CGFloat miterLimit;@property(nonatomic) CGFloat flatness;//是否用奇偶填充规则@property(nonatomic) BOOL usesEvenOddFillRule;*绘制虚线*pattern:C类型线性数据*count:pattern中数据个数*phase:起始位置- (void)setLineDash:(nullable const CGFloat *)pattern count:(NSInteger)count phase:(CGFloat)phase;- (void)getLineDash:(nullable CGFloat *)pattern count:(nullable NSInteger *)count phase:(nullable CGFloat *)phase;//填充、描边- (void)fill;- (void)stroke;//设置填充的混合模式- (void)fillWithBlendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;//设置描边的混合模式- (void)strokeWithBlendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;//修改当前图形上下文的绘图区域可见,随后的绘图操作导致呈现内容只有发生在指定路径的填充区域- (void)addClip;复制代码
CAShapeLayer
//路径,CASshapeLayer就是根据这个路径绘制图形的 @property(nullable) CGPathRef path; //填充内部的颜色,默认黑色。支持动画 @property(nullable) CGColorRef fillColor; //填充方式有两种 @property(copy) NSString *fillRule; //路径颜色,默认nil。支持动画 @property(nullable) CGColorRef strokeColor; //起点和终点,取值在0-1之间。于路径总长度成比例关系。支持动画 @property CGFloat strokeStart; @property CGFloat strokeEnd; //路径宽度。支持动画 @property CGFloat lineWidth; // 最大斜接长度。斜接长度指的是在两条线交汇处内角和外角之间的距离。默认10。支持动画 @property CGFloat miterLimit; //线端点类型 @property(copy) NSString *lineCap; //线连接类型 @property(copy) NSString *lineJoin; // 线型模板的起始位置。支持动画 @property CGFloat lineDashPhase; //线型模板,这是一个NSNumber的数组,索引从1开始记,奇数位数值表示实线长度,偶数位数值表示空白长度。 @property(nullable, copy) NSArray*lineDashPattern;复制代码
隐式动画
可以理解成图层的默认动画,但是可以通过CATransaction 进行控制
[CATransaction begin];[CATransaction setAnimationDuration:1.0];self.colorLayer.backgroundColor = [UIColor redColor];[CATransaction commit];复制代码
UIView关联的图层禁用隐式动画
显式动画
属性动画
CABaseAnimation *animation = [CABasicAnimation animation];animation.keyPath = @"backgroundColor";animation.toValue = (__bridge id)color.CGColor;animation.delegate = self;[self.colorLayer addAnimation:animation forKey:nil];复制代码
关键帧动画
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];animation.keyPath = @"backgroundColor";animation.duration = 2.0;animation.values = @[(__bridge id)color1.CGColor,(__bridge id)color2.CGColor,(__bridge id)color3.CGColor,(__bridge id)color4.CGColor];[self.colorLayer addAnimation:animation forKey:nil];复制代码
虚拟属性
旋转 tranform.rotation
CABaseAnimation *animation = [CABasicAnimation animation];animation.keyPath = @"tranform.rotation";animation.toValue = (__bridge id)color.CGColor;animation.duration = 2.0;animtaion.byValue = @(M_PI * 2);[self.colorLayer addAnimation:animation forKey:nil];复制代码
动画组
CAAnimationGroup
CAAnimationGroup *groupAnimation = [CAAnimationGroup animation];groupAnimation.animations = @[animations1,animations2];[self.colorLayer addAnimation:animation forKey:nil];复制代码
未完待续。。。