一、UIView和CALayer
-
关系
- 在创建UIView对象时,UIView内部会自动创建一个层(即CALayer对象),通过UIView的layer属性可以访问这个层。当UIView需要显示到屏幕上时,会调用drawRect:方法进行绘图,并且会将所有内容绘制在自己的层上,绘图完毕后,系统会将层拷贝到屏幕上,于是就完成了UIView的显示。
- 换句话说,UIView本身不具备显示的功能,是它内部的层才有显示功能。
- 两者都有树状层级结构,layer 内部有 SubLayers,View 内部有 SubViews.但是 Layer 比 View 多了个AnchorPoint
-
不同
- 两者最明显的区别是 View可以接受并处理事件,而 Layer 不可以.
- UIView主要是对显示内容的管理而 CALayer 主要侧重显示内容的绘制。
- 在做 iOS 动画的时候,修改非 RootLayer的属性(譬如位置、背景色等)会默认产生隐式动画,而修改UIView则不会。
-
修改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
-
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"); }
-
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"); }
-
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"); }
-
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
-
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
-
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
-
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
- 说到CAShapLayer就不得不说到UIBezierPath: UIBezierPath是在 UIKit 中的一个类,继承于NSObject,可以创建基于矢量的路径。使用此类可以定义常见的圆形、多边形等形状 。我们使用直线、弧(arc)来创建复杂的曲线形状。每一个直线段或者曲线段的结束的地方是下一个的开始的地方。每一个连接的直线或者曲线段的集合成为subpath。一个UIBezierPath对象定义一个完整的路径包括一个或者多个subpaths
- CAShapeLayer: CAShapeLayer顾名思义,继承于CALayer。 每个CAShapeLayer对象都代表着将要被渲染到屏幕上的一个任意的形状(shape)。具体的形状由其path(类型为CGPathRef)属性指定。 普通的CALayer是矩形,所以需要frame属性。CAShapeLayer初始化时也需要指定frame值,但 它本身没有形状,它的形状来源于其属性path 。CAShapeLayer有不同于CALayer的属性,它从CALayer继承而来的属性在绘制时是不起作用的
- 步骤:
1、新建UIBezierPath对象bezierPath
2、新建CAShapeLayer对象caShapeLayer
3、将bezierPath的CGPath赋值给caShapeLayer的path,即caShapeLayer.path = bezierPath.CGPath
4、把caShapeLayer添加到某个显示该图形的layer中
四、综合实例
时间: 2024-10-13 09:09:55