CoreAnimation练习
#import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self test]; [self test2]; [self test3]; [self test4]; [self test5]; [self test7]; } //- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ // // //} #pragma mark - 小方块 - (void)test{ CALayer *layer = [[CALayer alloc] init]; layer.bounds = CGRectMake(0, 0, 100, 100); layer.backgroundColor = [UIColor orangeColor].CGColor; layer.delegate = self; [self.view.layer addSublayer:layer]; layer.anchorPoint = CGPointMake(0.5, 0.5); layer.position = CGPointMake(100, 100); CABasicAnimation *ani = [[CABasicAnimation alloc] init]; ani.keyPath = @"transform.scale"; ani.fromValue = [NSNumber numberWithFloat:0.5]; ani.toValue = [NSNumber numberWithFloat:1.8]; ani.repeatCount = MAXFLOAT; ani.duration = 1.0f; // 当动画执行到toValue指定的状态时是从toValue的状态逆回去,还是直接跳到fromValue的状态再执行一遍 ani.autoreverses = YES; ani.fillMode = kCAFillModeForwards; ani.removedOnCompletion = NO; [layer addAnimation:ani forKey:nil]; } - (void)animationDidStart:(CAAnimation *)anim{ NSLog(@"动画开始"); } - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ NSLog(@"动画结束"); } - (void)test2{ CALayer *layer = [[CALayer alloc] init]; layer.bounds = CGRectMake(0, 0, 50, 50); layer.backgroundColor = [UIColor redColor].CGColor; layer.anchorPoint = CGPointMake(0, 0); layer.position = CGPointMake(0, 200); [self.view.layer addSublayer:layer]; CABasicAnimation *ani = [[CABasicAnimation alloc] init]; ani.keyPath = @"transform.translation.x"; ani.fromValue = [NSNumber numberWithFloat:60]; ani.toValue = [NSNumber numberWithFloat:300]; ani.autoreverses = YES; ani.fillMode = kCAFillModeForwards; ani.removedOnCompletion = NO; ani.duration = 1; ani.repeatCount = MAXFLOAT; [layer addAnimation:ani forKey:nil]; } - (void)test3{ CALayer *layer = [[CALayer alloc] init]; layer.bounds = CGRectMake(0, 0, 50, 50); layer.backgroundColor = [UIColor blueColor].CGColor; layer.anchorPoint = CGPointMake(0.5, 0); layer.position = CGPointMake(100, 0); [self.view.layer addSublayer:layer]; CABasicAnimation *ani = [[CABasicAnimation alloc] init]; ani.keyPath = @"transform.translation.y"; ani.fromValue = [NSNumber numberWithFloat:0]; ani.toValue = [NSNumber numberWithFloat:self.view.frame.size.height - 50]; ani.fillMode = kCAFillModeBoth; ani.removedOnCompletion = NO; ani.autoreverses = YES; ani.duration = 2; ani.repeatCount = MAXFLOAT; CABasicAnimation *ani2 = [[CABasicAnimation alloc] init]; ani2.keyPath = @"transform.scale"; ani2.fromValue = [NSNumber numberWithFloat:1]; ani2.toValue = [NSNumber numberWithFloat:2.8]; ani2.fillMode = kCAFillModeBoth; ani2.removedOnCompletion = NO; ani2.autoreverses = YES; ani2.duration = 1; ani2.repeatCount = MAXFLOAT; CABasicAnimation *ani3 = [[CABasicAnimation alloc] init]; ani3.keyPath = @"transform.rotation.y"; ani3.fromValue = [NSNumber numberWithFloat:1]; ani3.toValue = [NSNumber numberWithFloat:M_PI_2*2]; ani3.fillMode = kCAFillModeBoth; ani3.removedOnCompletion = NO; ani3.autoreverses = YES; ani3.duration = 0.5; ani3.repeatCount = MAXFLOAT; CAAnimationGroup *group = [[CAAnimationGroup alloc] init]; group.duration = 2; group.animations = @[ani,ani2,ani3]; group.repeatCount = MAXFLOAT; group.autoreverses = YES; [layer addAnimation:group forKey:nil]; } - (void)test5{ CALayer *layer = [[CALayer alloc] init]; layer.bounds = CGRectMake(0, 0, 50, 50); layer.backgroundColor = [UIColor greenColor].CGColor; layer.anchorPoint = CGPointMake(0.5, 0); layer.position = CGPointMake(100, 0); [self.view.layer addSublayer:layer]; CAKeyframeAnimation *ani = [[CAKeyframeAnimation alloc] init]; ani.keyPath = @"position"; CGPoint p1 = CGPointMake(80, 80); CGPoint p2 = CGPointMake(250, 80); CGPoint p3 = CGPointMake(250, 250); CGPoint p4 = CGPointMake(80, 250); CGPoint p5 = CGPointMake(80, 80); // ani.values = @[[NSValue valueWithCGPoint:p1], // [NSValue valueWithCGPoint:p2], // [NSValue valueWithCGPoint:p3], // [NSValue valueWithCGPoint:p4], // [NSValue valueWithCGPoint:p5]]; // ani.keyTimes = @[@0.25,@0.25,@0.25,@0.25]; CGMutablePathRef path = CGPathCreateMutable(); // CGPathAddRect(path, NULL, CGRectMake(0, 0, 200, 200)); // CGPathAddEllipseInRect(path, NULL, CGRectMake(0, 0, 200, 200)); CGPathAddArc(path, NULL, 200, 200, 100, 0, 2*M_PI, YES); // CGPathMoveToPoint(path, NULL, 0, 0); // CGPathAddLineToPoint(path, NULL, 300, 300); ani.path = path; ani.duration = 2; ani.repeatCount = MAXFLOAT; ani.removedOnCompletion = NO; ani.fillMode = kCAFillModeForwards; // ani.autoreverses = YES; [layer addAnimation:ani forKey:nil]; } - (void)test4{ CALayer *layer = [[CALayer alloc] init]; layer.bounds = CGRectMake(0, 0, 50, 50); layer.backgroundColor = [UIColor grayColor].CGColor; layer.anchorPoint = CGPointMake(0.5, 0); layer.position = CGPointMake(100, 0); [self.view.layer addSublayer:layer]; CASpringAnimation *ani = [[CASpringAnimation alloc] init]; ani.keyPath = @"position"; ani.fromValue = [NSValue valueWithCGPoint:CGPointMake(100, 100)]; ani.toValue = [NSValue valueWithCGPoint:CGPointMake(100, 400)]; //这个属性设置弹簧重物的质量 会影响惯性 必须大于0 默认为1 ani.mass = 1; //设置弹簧的刚度系数,必须大于0 默认为100 这个越大 则回弹越快 ani.stiffness = 50; //阻尼系数 默认为10 必须大于0 这个值越大 回弹的幅度越小 ani.damping = 2.5; //初始速度 ani.initialVelocity = 0; NSLog(@"ani.settlingDuration %lf",ani.settlingDuration); ani.duration = ani.settlingDuration; ani.repeatCount = MAXFLOAT; ani.removedOnCompletion = NO; ani.fillMode = kCAFillModeForwards; // ani.autoreverses = YES; [layer addAnimation:ani forKey:nil]; } - (void)test7{ // CALayer *layer = [[CALayer alloc] init]; // layer.bounds = CGRectMake(0, 0, 50, 50); // layer.backgroundColor = [UIColor grayColor].CGColor; // layer.anchorPoint = CGPointMake(0.5, 0.5); // layer.position = CGPointMake(self.view.frame.size.width - 80, 40); // // [self.view.layer addSublayer:layer]; UIImageView *imgView = [[UIImageView alloc] init]; imgView.frame = CGRectMake(self.view.frame.size.width - 120, 40, 100, 100); imgView.image = [UIImage imageNamed:@"通风"]; [self.view addSubview:imgView]; CALayer *layer = imgView.layer; layer.anchorPoint = CGPointMake(0.5, 0.5); CABasicAnimation *ani = [[CABasicAnimation alloc] init]; ani.keyPath = @"transform.rotation.z"; ani.fromValue = @0; ani.toValue = [NSNumber numberWithFloat:2*M_PI]; ani.removedOnCompletion = NO; ani.fillMode = kCAFillModeForwards; ani.repeatCount = MAXFLOAT; ani.duration = 3; [layer addAnimation:ani forKey:nil]; } @end
-
keyPath: 决定基础动画的类型,该值不能随便取,一旦取错就达不到想要的效果。要改变位置就取position,要改变透明度就取opacity,要等比例缩放就取transform.scale...更多key请看下面的表1,要尽量能记住这些内容
-
fromValue: 动画的起始状态值,虽然iOS文档给出的类型是id,不过这里应该传NSValue对象,比如NSNumber(NSNubmer继承自NSValue)。其具体含义
-
autoreverse: 当动画执行到toValue指定的状态时是从toValue的状态逆回去,还是直接跳到fromValue的状态再执行一遍
-
fileMode: fillMode的作用就是决定当前对象过了非active时间段的行为. 非active时间段是指动画开始之前以及动画结束之后。如果是一个动画CAAnimation,则需要将其removedOnCompletion设置为NO,要不然fillMode不起作用. 下面来讲各个fillMode的意义:
-
kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态
-
kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态
-
kCAFillModeBackwards 这个和kCAFillModeForwards是相对的,就是在动画开始前,你只要将动画加入了一个layer,layer便立即进入动画的初始状态。因为有可能出现fromValue不是目前layer的初始状态的情况,如果fromValue就是layer当前的状态,则这个参数就没太大意义。
-
kCAFillModeBoth 理解了上面两个,这个就很好理解了,这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态.