iOS之核心动画

2018-02-09 19:27:13来源:cnblogs.com作者:东方🐺人点击

分享
1.将动画的所有方法封装到一个类里面MyCAHelper.h#import <Foundation/Foundation.h>#import <QuartzCore/QuartzCore.h>#define kCAHelperAlphaAnimation @"opacity"; // 淡入淡出动画#define kCAHelperScaleAnimation @"transform.scale"; // 比例缩放动画#define kCAHelperRotationAnimation @"transform.rotation"; // 旋转动画#define kCAHelperPositionAnimation @"position"; // 平移位置动画@interface MyCAHelper : NSObject#pragma mark - 基本动画统一调用方法+ (CABasicAnimation *)myBasicAnimationWithType:(NSString *)animationTypeduration:(CFTimeInterval)durationfrom:(NSValue *)fromto:(NSValue *)toautoRevereses:(BOOL)autoRevereses;#pragma mark - 关键帧动画方法#pragma mark 摇晃动画+ (CAKeyframeAnimation *)myKeyShakeAnimationWithDuration:(CFTimeInterval)durationangle:(CGFloat)anglerepeatCount:(CGFloat)repeatCount;#pragma mark 贝塞尔路径动画+ (CAKeyframeAnimation *)myKeyPathAnimationWithDuration:(CFTimeInterval)durationpath:(UIBezierPath *)path;#pragma mark 弹力仿真动画+ (CAKeyframeAnimation *)myKeyBounceAnimationFrom:(CGPoint)fromto:(CGPoint)toduration:(CFTimeInterval)duration;@endMyCAHelper.m#import "MyCAHelper.h"@implementation MyCAHelper#pragma mark - 基本动画统一调用方法+ (CABasicAnimation *)myBasicAnimationWithType:(NSString *)animationTypeduration:(CFTimeInterval)durationfrom:(NSValue *)fromto:(NSValue *)toautoRevereses:(BOOL)autoRevereses{        // 1. 实例化一个CA动画对象        CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:animationType];                // 2. 设置动画属性        [anim setDuration:duration];                [anim setFromValue:from];        [anim setToValue:to];                [anim setAutoreverses:autoRevereses];                return anim;}#pragma mark - 关键帧动画方法#pragma mark 摇晃动画+ (CAKeyframeAnimation *)myKeyShakeAnimationWithDuration:(CFTimeInterval)durationangle:(CGFloat)anglerepeatCount:(CGFloat)repeatCount{        // 1. 初始化动画对象实例        CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];                // 2. 设置动画属性        [anim setDuration:duration];                [anim setValues:@[@(angle), @(-angle), @(angle)]];                [anim setRepeatCount:repeatCount];                return anim;}#pragma mark 贝塞尔路径动画+ (CAKeyframeAnimation *)myKeyPathAnimationWithDuration:(CFTimeInterval)durationpath:(UIBezierPath *)path{        // 1. 初始化动画对象实例        CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"];                // 2. 设置动画属性        [anim setDuration:duration];                [anim setPath:path.CGPath];                return anim;}#pragma mark 弹力仿真动画+ (CAKeyframeAnimation *)myKeyBounceAnimationFrom:(CGPoint)fromto:(CGPoint)toduration:(CFTimeInterval)duration{        // 是一个基于路径的动画        // 首先定义一个路径,记录弹力仿真的整个路径        CGMutablePathRef path = CGPathCreateMutable();                // 弹力仿真路径创建代码        // 计算起始点与目标点之间的位置偏移量,这个偏移量的目的是为了能够计算出小球第一次延伸的长度        CGFloat offsetX = from.x - to.x;        CGFloat offsetY = from.y - to.y;                // 1. 移动到起始点        CGPathMoveToPoint(path, NULL, from.x, from.y);        // 2. 将目标点的坐标添加到路径之中        CGPathAddLineToPoint(path, NULL, to.x, to.y);        // 3. 设置小球的弹力因子        CGFloat offsetDivider = 4.0f;                while (YES) {                // 加延伸方向的路径                CGPathAddLineToPoint(path, NULL, to.x + offsetX / offsetDivider,                to.y + offsetY / offsetDivider);                                // 再次将目标点添加到路径                CGPathAddLineToPoint(path, NULL, to.x, to.y);                                // 弹力因子递增,保证越来越接近目标点                offsetDivider += 6.0f;                                // 当小球的当前位置距离目标点足够小,我们退出循环                if ((abs(offsetX / offsetDivider) < 10.0f)                && (abs(offsetY / offsetDivider) < 10.0f)) {                                    break;                }        }        CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"];        [anim setPath:path];                // 释放路径        CGPathRelease(path);                [anim setDuration:duration];                return anim;}@end#import "ViewController.h"#import "MyCAHelper.h"@interface ViewController (){        UIView *_demoView;        CGPoint location;}@[email protected] ViewController- (void)viewDidLoad{        [super viewDidLoad];        // Do any additional setup after loading the view, typically from a nib.        [self.view setBackgroundColor:[UIColor lightGrayColor]];                _demoView = [[UIView alloc]initWithFrame:CGRectMake(50, 50, 100, 100)];        [_demoView setBackgroundColor:[UIColor whiteColor]];        [self.view addSubview:_demoView];}- (void)didReceiveMemoryWarning{        [super didReceiveMemoryWarning];        // Dispose of any resources that can be recreated.}- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{        UITouch *touch = [touches anyObject];        location = [touch locationInView:self.view];                // [_demoView setCenter:location];        /**         1.测试基本动画        */        // CABasicAnimation *anim = [self testBasic1];        // [anim setRepeatCount:3];        //         // [_demoView.layer addAnimation:anim forKey:nil];        /**        2.测试弹力仿真动画效果        */        // [_demoView.layer addAnimation:[self test1:_demoView.center to:location] forKey:nil];        /**        3.测试路径关键帧动画        */        // [_demoView.layer addAnimation:[self test2] forKey:nil];        // [_demoView.layer addAnimation:[self test4:_demoView.center to:location] forKey:nil];        /**        4.测试摇晃关键帧动画        */        // 点击屏幕,开始摇晃,再次点击,停止摇晃        // CAAnimation *anim = [_demoView.layer animationForKey:@"shakeAnimation"];        // if (anim) {        // [_demoView.layer removeAnimationForKey:@"shakeAnimation"];        // } else {        // [_demoView.layer addAnimation:[self test5] forKey:@"shakeAnimation"];        // }        CAKeyframeAnimation *anim = [self test1:_demoView.center to:location];        [_demoView.layer addAnimation:anim forKey:nil];}-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{        // 需要在这里对不同对象的动画方法进行完成处理!        [_demoView setCenter:location];        NSLog(@"%@", NSStringFromCGPoint(_demoView.center));}#pragma mark - 重构方法测试#pragma mark 测试贝塞尔路径关键帧动画- (CAKeyframeAnimation *)test5{        return [MyCAHelper myKeyShakeAnimationWithDuration:0.2 angle:M_PI_4 / 18 repeatCount:MAXFLOAT];}#pragma mark 测试贝塞尔路径关键帧动画- (CAKeyframeAnimation *)test4:(CGPoint)from to:(CGPoint)to{        UIBezierPath *path = [UIBezierPath bezierPath];                // 有两个控制点去挤出的曲线,能挤出S型的曲线        [path moveToPoint:from];        [path addCurveToPoint:to controlPoint1:CGPointMake(320, 0) controlPoint2:CGPointMake(0, 460)];                return [MyCAHelper myKeyPathAnimationWithDuration:2.0 path:path];}#pragma mark 测试贝塞尔路径关键帧动画- (CAKeyframeAnimation *)test3:(CGPoint)from to:(CGPoint)to{        UIBezierPath *path = [UIBezierPath bezierPath];                // 只有一个控制点去挤出的曲线        [path moveToPoint:from];        [path addQuadCurveToPoint:to controlPoint:CGPointMake(320, 230)];                return [MyCAHelper myKeyPathAnimationWithDuration:2.0 path:path];}#pragma mark 测试路径关键帧动画- (CAKeyframeAnimation *)test2{        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 100, 100)];        return [MyCAHelper myKeyPathAnimationWithDuration:2.0 path:path];}#pragma mark 测试弹力仿真动画效果- (CAKeyframeAnimation *)test1:(CGPoint)from to:(CGPoint)to{        CAKeyframeAnimation *anim = [MyCAHelper myKeyBounceAnimationFrom:from to:to duration:1.5];        [anim setFillMode:kCAFillModeForwards];        [anim setRemovedOnCompletion:NO];                [anim setDelegate:self];                return anim;}- (CABasicAnimation *)testBasic1{        return [MyCAHelper myBasicAnimationWithType:@"opacity" duration:1.0 from:@(1.0) to:@(0.3) autoRevereses:YES];}@end

一、核心动画概念

-导入QuartzCore.framework框架

1⃣ 开发步骤
1.初始化一个动画对象(CAAnimation)并且设置一些动画相关属性

2.CALayer中很多属性都可以通过CAAnimation实现动画效果,包括:opacity、position、transform、bounds、contents等(可以在API文档中搜索:CALayer Animatable Properties)

3.添加动画对象到层(CALayer)中,开始执行动画

4.通过调用CALayer的addAnimation:forKey增加动画到层(CALayer)中,这样就能触发动画。通过调用removeAnimationForKey可以停止层中的动画

5.Core Animation的动画执行过程都是后台操作的,不会阻塞主线程

2⃣ 属性
1.duration:动画的持续时间

2.repeatCount:重复次数(HUGE_VALF、MAX FLOAT无限重复)

3.repeatDuration:重复时间(用的很少)

4.removedOnCompletion:默认为Yes。动画执行完后默认会从图层删除掉

5.fillMode
6.biginTime
7.timingFunction:速度控制函数,控制动画节奏

8.delegate


二、基础动画(CABasicAnimation)
如果只是实现简单属性变化的动画效果,可以使用UIView的块动画替代基本动画

1⃣ 属性说明
-fromValue:keyPath相应属性值的初始值

-toValue:keyPath相应属性的结束值

2⃣ 动画过程说明:

-随着动画的就行,在duration的持续时间内,keyPath相应的属性值从fromValue渐渐变为toValue

-keyPath内容是CALayer的可动画Animation属性

-如果fillMode=kCAFillModeForwards同时removedOnCompletion=NO,那么在动画执行完毕后,图层会保持显示动画执行后的状态,但在实质上,图层的属性值还是动画执行前的初始值,并没有真正改变

3⃣ 代码实现
位移需要考虑目标点设定的问题

三、关键帧动画(CAKeyframeAnimation)

基础动画只能从一个值到另一个值,关键帧动画可以用一个数组保存一系列值

1⃣ 属性说明
-values:所有的值(用的较少)

-path:路线(如果设置了path,那么values将被忽略)

-keyTimes:可以为对应的关键帧制定对应的时间点,取值范围是0到1.0

2⃣ 过程步骤
-初始化自定义视图

-点击屏幕,执行动画

1.指定点平移动画(values)

2.路径平移动画(path C语言框架CGMutablePathRef,需要手动释放内存)

3.贝塞尔路径动画(OC框架UIBezierPath)

4.摇晃动画(修改旋转角度)

3⃣ 代码重构
如上代码,重构在了一起

四、动画组
动画是可以并发执行的

-定义一个group组

-定义动画
-将动画加入group组

-可以给组设置属性

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{        UITouch *touch = [touches anyObject];        CGPoint location = [touch locationInView:self.view];                [_demoView setBackgroundColor:[UIColor redColor]];                // 1. 定义动画组        CAAnimationGroup *group = [CAAnimationGroup animation];        // 定义一组动画        // 淡入淡出动画        CABasicAnimation *alpha = [MyCAHelper myBasicAnimationWithType:kCAHelperAlphaAnimation duration:1.0 from:@(1.0) to:@(0.3) autoRevereses:YES];        // 旋转动画        CABasicAnimation *rotation = [MyCAHelper myBasicAnimationWithType:kCAHelperRotationAnimation duration:2.0 from:@(-M_PI_2) to:@(M_PI_2) autoRevereses:NO];        // 缩放动画        CABasicAnimation *scale = [MyCAHelper myBasicAnimationWithType:kCAHelperScaleAnimation duration:0.5 from:@(1.0) to:@(0.1) autoRevereses:YES];                // 关键帧路径动画,弹力仿真动画效果        CAKeyframeAnimation *path = [self test1:_demoView.center to:location];                // 2. 设置动画组属性        [group setAnimations:@[alpha, path, rotation, scale]];                // 设置动画的时长        [group setDuration:4.0];                // 3. 将动画组添加到图层        [_demoView.layer addAnimation:group forKey:nil];}

五、转场动画-CATransition
1⃣属性说明
-type:动画过渡类型

-subtype:动画过渡方向

-startProgress:动画起点(在整体动画的百分比)

-endProgress:动画终点(在整体动画的百分比)

-增加一个转场演示视图

-增加轻扫手势
-在轻扫手势方法中

1.更改演示视图内容

2.创建转场动画效果

3.将转场动画添加到视图的图层

// 轻扫手势操作- (void)swipeAction:(UISwipeGestureRecognizer *)sender{        // 通过轻扫手势,让切换出来的视图是蓝色的        if (_demoView.tag == 0) {        [_demoView setBackgroundColor:[UIColor blueColor]];        [_demoView setTag:1];        }         else         {        [_demoView setBackgroundColor:[UIColor redColor]];        [_demoView setTag:0];        }                // 根据视图内容我们来实现专场动画        CATransition *anim = [CATransition animation];        // 设置专场动画的过渡类型        [anim setType:@"cameraIrisHollowClose"];        // 需要根据手势的方向,来决定专场动画的动画方向        // 注意:在转场动画中,动画方向的左右是和手势的方向相反的        if (sender.direction == UISwipeGestureRecognizerDirectionLeft) {        [anim setSubtype:kCATransitionFromRight];        } else {        [anim setSubtype:kCATransitionFromLeft];        }                [_demoView.layer addAnimation:anim forKey:nil];}- (void)viewDidLoad{        [super viewDidLoad];        // Do any additional setup after loading the view, typically from a nib.        // 1. 实例化自定义视图        _demoView = [[UIView alloc]initWithFrame:self.view.bounds];        [_demoView setBackgroundColor:[UIColor redColor]];                [self.view addSubview:_demoView];                // 2. 增加轻扫手势        UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc]        initWithTarget:self        action:@selector(swipeAction:)];        [swipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft];        [_demoView addGestureRecognizer:swipeLeft];                UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc]        initWithTarget:self        action:@selector(swipeAction:)];        [swipeRight setDirection:UISwipeGestureRecognizerDirectionRight];        [_demoView addGestureRecognizer:swipeRight];}

六、UIView的转场动画-双视图

+(void)transitionWithView:(UIView*)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void(^)(void))animations completion:(void(^)(BOOL finished))completion;1⃣参数说明-duration:动画的持续时间-view:需要进行转场动画的视图-options:转场动画的类型-animations:将改变视图属性的代码放在这个Block里-completion:动画结束后,自动调用的[email protected] ViewController (){        UIImageView *_demoImageView;        UIImageView *_demoImageView2;}@[email protected] ViewController- (void)viewDidLoad{        [super viewDidLoad];        // Do any additional setup after loading the view, typically from a nib.        // 实例化第一个UIImageView的对象        _demoImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"1.jpg"]];        [self.view addSubview:_demoImageView];                // 实例化第二个UIImageView对象        // 注意:在双视图转场动画中,不要将第二个视图添加到主视图        _demoImageView2 = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"2.jpg"]];}- (void)didReceiveMemoryWarning{        [super didReceiveMemoryWarning];        // Dispose of any resources that can be recreated.}- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{        // 单击屏幕的时候,实现转场动画效果        [self animation1];}#pragma mark - 单视图的转场动画- (void)animation2{        UIImageView *from;        UIImageView *to;                if (_demoImageView.superview) {        from = _demoImageView;        to = _demoImageView2;        }         else         {        from = _demoImageView2;        to = _demoImageView;        }                [UIView transitionFromView:from toView:to duration:1.0f options:UIViewAnimationOptionTransitionCrossDissolve completion:^(BOOL finished) {        NSLog(@"image view1 的主视图: %@", _demoImageView.superview);        NSLog(@"image view2 的主视图: %@", _demoImageView2.superview);        }];}#pragma mark - 单视图的转场动画- (void)animation1{        [UIView transitionWithView:_demoImageView duration:1.0f options:UIViewAnimationOptionTransitionCurlUp animations:^{        // 在动画块代码中设置视图内容变化                if (_demoImageView.tag == 0) {                        [_demoImageView setImage:[UIImage imageNamed:@"2.jpg"]];                        [_demoImageView setTag:1];                }                 else                 {                        [_demoImageView setImage:[UIImage imageNamed:@"1.jpg"]];                        [_demoImageView setTag:0];                }        } completion:nil];}

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台