CAKeyframeAnimation和CABaseAnimation都属于CAPropertyAnimatin的子类。CABaseAnimation只能从一个数值(fromValue)变换成另一个数值(toValue),而CAKeyframeAnimation则会使用一个NSArray保存一组关键帧。
#import "ViewController.h"
@interface ViewController ()
//背景
@property (nonatomic, strong) CALayer *layer;
//花瓣
@property (nonatomic, strong) CALayer *petalLayer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
[self.view.layer addSublayer:self.layer];
[self.view.layer addSublayer:self.petalLayer];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self demo2:[[touches anyObject]locationInView:self.view]];
}
- (void)demo2:(CGPoint)toPoint{
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:self.petalLayer.position];
[path addCurveToPoint:toPoint controlPoint1:CGPointMake(100, 100) controlPoint2:CGPointMake(52, 600)];
animation.path = path.CGPath;
animation.duration = 3;
animation.removedOnCompletion = NO;
animation.fillMode = kCAScrollBoth;
// 自动计算每个运动轨迹之间补间动画的时间
animation.calculationMode = kCAAnimationCubicPaced;
animation.rotationMode = kCAAnimationRotateAuto;
[self.petalLayer addAnimation:animation forKey:@""];
}
- (CALayer *)petalLayer{
if (_petalLayer) {
return _petalLayer;
}
_petalLayer = [CALayer layer];
_petalLayer.position = CGPointMake(self.view.center.x, 50);
UIImage *image =[UIImage imageNamed:@"huaban-1"];
_petalLayer.bounds = CGRectMake(0, 0, image.size.width, image.size.height);
_petalLayer.contents = (id)image.CGImage;
return _petalLayer;
}
- (CALayer *)layer{
if (_layer) {
return _layer;
}
_layer = [CALayer layer];
_layer.position = CGPointMake(self.view.center.x, self.view.center.y+100);
UIImage *image =[UIImage imageNamed:@"background"];
_layer.bounds = CGRectMake(0, 0, image.size.width/2, image.size.height/2);
_layer.contents = (id)image.CGImage;
return _layer;
}
@end
效果图如下
第二种效果
// 关键帧动画NO.2
#import "PatingView.h"
@implementation PatingView
- (UIBezierPath *)path{
if (_path!=nil) {
return _path;
}
_path = [UIBezierPath bezierPath];
return _path;
}
- (CALayer *)pointLayer{
if (_pointLayer) {
return _pointLayer;
}
_pointLayer = [CALayer layer];
_pointLayer.frame = CGRectMake(0, -20, 15, 15);
_pointLayer.cornerRadius = 15/2;
_pointLayer.backgroundColor = [UIColor colorWithRed:0.917 green:0.5309 blue:1.0 alpha:1.0].CGColor;
_pointLayer.shadowOpacity = 0.8;
_pointLayer.shadowRadius = 3;
_pointLayer.shadowColor = [UIColor colorWithRed:1.0 green:0.6648 blue:0.0006 alpha:1.0].CGColor;
[self.layer addSublayer:_pointLayer];
return _pointLayer;
}
/* - (CALayer *)pointLayer{ if (_pointLayer) { return _pointLayer; } CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer]; replicatorLayer.frame = self.bounds; replicatorLayer.instanceCount = 30; replicatorLayer.instanceDelay = 0.5; replicatorLayer.backgroundColor = [UIColor clearColor].CGColor; [self.layer addSublayer:replicatorLayer]; _pointLayer = [CALayer layer]; _pointLayer.frame = CGRectMake(0, -20, 15, 15); _pointLayer.cornerRadius = 15/2; _pointLayer.backgroundColor = [UIColor colorWithRed:0.917 green:0.5309 blue:1.0 alpha:1.0].CGColor; _pointLayer.shadowOpacity = 0.8; _pointLayer.shadowRadius = 3; _pointLayer.shadowColor = [UIColor colorWithRed:1.0 green:0.6648 blue:0.0006 alpha:1.0].CGColor; [replicatorLayer addSublayer:_pointLayer]; return _pointLayer; } */
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.path moveToPoint:[[touches anyObject] locationInView:self]];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.path addLineToPoint:[[touches anyObject] locationInView:self]];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
[[UIColor colorWithRed:0.0444 green:0.4332 blue:1.0 alpha:1.0] set];
self.path.lineWidth = 5;
[self.path stroke];
}
- (void)start{
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
animation.path = self.path.CGPath;
animation.duration = 5;
animation.repeatCount = HUGE;
[self.pointLayer addAnimation:animation forKey:@"move"];
}
@end
效果图如下
动画组可以让动画同时执行且不相互影响,他有一个数组animations:动画的数组;动画组设置的持续时间会影响到动画组内部的动画持久时间动画组。
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
[self.view.layer addSublayer:self.layer];
[self.view.layer addSublayer:self.petalLayer];
}
- (CALayer *)petalLayer{
if (_petalLayer) {
return _petalLayer;
}
_petalLayer = [CALayer layer];
_petalLayer.position = CGPointMake(self.view.center.x, 50);
UIImage *image =[UIImage imageNamed:@"huaban-1"];
_petalLayer.bounds = CGRectMake(0, 0, image.size.width, image.size.height);
_petalLayer.contents = (id)image.CGImage;
return _petalLayer;
}
- (CALayer *)layer{
if (_layer) {
return _layer;
}
_layer = [CALayer layer];
_layer.position = CGPointMake(self.view.center.x, self.view.center.y+100);
UIImage *image =[UIImage imageNamed:@"background"];
_layer.bounds = CGRectMake(0, 0, image.size.width/2, image.size.height/2);
_layer.contents = (id)image.CGImage;
return _layer;
}
- (void)animationGroup:(CGPoint)endPoint{
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = @[[self move:endPoint], [self moveToBig]];
animationGroup.duration = 5;
/* 动画组中设置的时间控制类属性会影响到动画组中设置的时间控制类属性 在动画组中统一设置媒体时间控制类属性,入股需要单独设置,动画组中必须未设置相关属性 1.CAMediaTiming媒体时间类协议 核心动画关于时间类的控制 是遵守了CAMediaTiming中的协议内容 1.beginTime 动画开始的时间 默认为0 2.duration 动画的持续时间 默认为0 持续时间 受速度的影响 实际的动画完成时间 = 持续时间/速度 3.speed 动画播放的速度 默认为1 速度设置成0 可以暂停动画 speed 2秒 duration 60秒 动画真正播放完成的时间 30秒 4.timeOffset 动画播放时间的偏移量 5.repeatCount 动画的循环次数 默认是0 只播放一次 6.repeatDuration 动画循环的持续时间 只能设置其中的一个属性 repeatCount/repeatDuration 7.autoreverses 是否以动画的形式 返回到播放之前的状态 8.fillMode 设置当前对象在非活动时间段的状态 要想fillMode有效 需设置removedOnCompletion = NO kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态 kCAFillModeBackwards 立即进入动画的初始状态并等待动画开始 kCAFillModeBoth 动画加入后开始之前 layer处于动画初始状态 动画结束后layer保持动画最后的状态 kCAFillModeRemoved 默认值 动画结束后 layer会恢复到之前的状态 */
animationGroup.removedOnCompletion = NO;
animationGroup.fillMode = kCAFillModeBoth;
[self.petalLayer addAnimation:animationGroup forKey:@""];
}
/** * 让图层移动的动画 * * @param endPoint 终点 * * @return 移动的动画 */
- (CAKeyframeAnimation *)move:(CGPoint)endPoint{
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
// 贝塞尔路径
UIBezierPath *path = [UIBezierPath bezierPath];
// 设置起始点
[path moveToPoint:self.petalLayer.position];
/** * 画曲线 * * @param ToPoint 终点 * *controlPoint1、controlPoint2 控制点 */
[path addCurveToPoint:endPoint controlPoint1:CGPointMake(50, 200) controlPoint2:CGPointMake(300, 400)];
animation.path = path.CGPath;
// kCAAnimationPaced 节奏动画(不是匀速)
// kCAAnimationCubicPaced
animation.calculationMode = kCAAnimationCubicPaced;
return animation;
}
//放大
- (CABasicAnimation *)moveToBig{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@""];
animation.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, CGRectGetWidth(self.petalLayer.bounds)*1.3, CGRectGetHeight(self.petalLayer.bounds)*1.3)];
return animation;
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self animationGroup:[[touches anyObject]locationInView:self.view]];
}
@end
官方文档只提供了四种效果:
endProgress 结束的进度(0-1)
注意:私有api,不建议开发者们使用。因为苹果公司不提供维护,并且有可能造成你的app审核不通过
示例
#import "ViewController.h"
#import "NextViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)next:(id)sender {
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
NextViewController *nextVC = [storyBoard instantiateViewControllerWithIdentifier:@"NextViewController"];
CATransition *animation = [CATransition animation];
animation.type = @"rippleEffect";
animation.duration = 3;
[self.navigationController.view.layer addAnimation:animation forKey:@""];
[self.navigationController pushViewController:nextVC animated:YES];
}
@end
NextViewController.m中
#import "NextViewController.h"
@interface NextViewController ()
@end
@implementation NextViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
CATransition *animation = [CATransition animation];
animation.type = kCATransitionFade;
animation.subtype = kCATransitionFromLeft;
animation.duration = 3;
[self.navigationController.view.layer addAnimation:animation forKey:@""];
[self.navigationController popViewControllerAnimated:NO];
}
其实,任何复杂的动画其实都是由一个个简单的动画组装而成的,只要我们善于分解和组装,我们就能实现出满意的效果。动画其实也不是那么难。