欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【iOS】一个取巧的弹出式动画实现以及后续的iOS动画学习(第一部分:基于CALayer的Core Animation框架)

程序员文章站 2024-03-22 21:56:52
...

二月中上班,开始开年需求,现在到三月初算是基本完成,也在测试之前趁着有那么一点空闲时间和精力记录下一些开发中遇到的问题。

这次记录下的是一个简单的动画效果实现。当时时间比较紧,用了一个取巧的动画实现(实际原因是没看懂CA动画怎么用),因此在这里记录下来,同时研究一下CA动画。


需求分析

(不知道怎么设置成循环,似乎只能刷新看一次)

【iOS】一个取巧的弹出式动画实现以及后续的iOS动画学习(第一部分:基于CALayer的Core Animation框架)

这个动画效果分为两部分,要求其实有三:

1.图案从小到大的弹出(从0-X秒)

2.总共三张图片的循环播放(从0-N秒,X<N)

3.动画播放一定时间后消失(N秒后消失)


取巧实现

先上我临时想出的方法

1.轮播图片的动画效果其实UIImageView就能实现

UIImageView *imageView = [[UIImageView alloc]initWithFrame:
    CGRectMake((rewardFinsihView.frame.size.width)/2, (rewardFinsihView.frame.size.height)/2, 0.f, 0.f)];
imageView.backgroundColor = [UIColor clearColor];
imageView.animationImages=imageArray;//imageArray就是一个包含UIImage数据的数组
imageView.animationDuration=0.4;
imageView.animationRepeatCount=5;
[rewardFinsihView addSubview:imageView];//rewardFinsihView就是背景view
[imageView startAnimating];

参数都很好理解:

animationImages就是要轮播的图片集

animationDuration就是轮播一次的时间(以秒为单位)

animationRepeatCount就是轮播次数

startAnimating开始动画

2.如果第一步实现决定使用UIImageView,那么弹出效果实际上就是一个UIImageView从小变大。

注意第一步设置imageView的frame.size为0,frame.origin为背景中心

接下来的代码就是

[UIView animateWithDuration:0.3 
    animations:^{imageView.frame = CGRectMake((rewardFinsihView.frame.size.width - 202.f)/2, (rewardFinsihView.frame.size.height - 130.f)/2, 202.f, 130.f);} 
    completion:^(BOOL finished){
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [imageView stopAnimating];
                [imageView removeFromSuperview];//把显示动画效果的UIImageView移除
                [rewardFinsihView removeFromSuperview];//把背景移除
                [[NSNotificationCenter defaultCenter] postNotificationName:kXXScriptRewardDidFinishNotification object:nil];//发出完成业务的通知
            });
    }];

这个也很容易理解。

animateWithDuration定义了整个放大的动画过程的时间(以秒为单位)

animation里面定义了放大后的imageView大小(同理可猜测这个自带的动画效果可以对其他一些属性也有效果)

completion就是动画完成之后的回调了,由于放大之后还需要播放几次动画,因此使用dispatch_after延迟一点时间执行完成动画后的操作(记得停止imageView自己的动画)。

实现的效果和上图差不多,可调的就是两个动画的持续时间、速度这些东西,只会影响表现效果。


后续学习

感觉自己的方法始终是歪门邪道,因此趁着还原之前一点时间补一下动画相关的东西,看看这次能不能看的懂。

下面记录的内容可能网上有很多,权且当作个人学习笔记吧。

iOS开发中实现动画效果通常有三种方式。

1.基于CALayerCore Animation框架,这是动画的基础框架。

2.基于UIView,为了方便实现简单的动画封装的UIView Animation。也就是我上面取巧方法的一部分用到的封装。

3.在游戏开发中经常用到的基于物理模拟的动画框架UIKit Dynamics

这里先了解下第一种:

基于CALayer的Core Animation框架

CA(Core Animation,核心动画)类图

【iOS】一个取巧的弹出式动画实现以及后续的iOS动画学习(第一部分:基于CALayer的Core Animation框架)

在CAAnimation中可以实现代理方法 <CAAnimationDelegate>,字段含义可查开发文档。

//Tells the delegate the animation has started.
- (void)animationDidStart:(CAAnimation *)anim;

//Tells the delegate the animation has ended.
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;

使用 addAnimation:forKey 为view view.layer 添加动画

一、先看看基本动画

基本动画CABasicAnimation继承CAPropertyAnimation,有两个要搞清楚的概念:

1. KeyPath。虽然设置的是一个字符串,但实际是标识了需要改变的属性类型(CALayer的可动画属性)

比如设置@"position.x",意思就是这个动画变化的是添加了该动画的view(实际应该是layer)的x横向位置

x的初始值由 fromValue 决定,终止值由 toValue 决定。

一句话概括:随着动画的进行,在长度为duration的持续时间内,keyPath相应属性的值fromValue渐渐地变为toValue

2. timingFunction。动画随时间运行的关系,直译“时间函数”。

CA提供了两种方式创建时间函数CAMediaTimingFunctionName。

一种是使用常量设置

+ (instancetype)functionWithName:(CAMediaTimingFunctionName)name;

kCAMediaTimingFunctionEaseIn 淡入:慢 -》快

kCAMediaTimingFunctionEaseOut 淡出:快 -》慢

kCAMediaTimingFunctionEaseInEaseOut 淡入淡出

kCAMediaTimingFunctionDefault 默认无变化

一种是传入两个控制点创建贝塞尔曲线(cubic Bézier)函数

+ (instancetype)functionWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;

http://cubic-bezier.com/ 这里可以看到数值对应的效果

其实挺好理解的,横轴是时间,纵轴是变化进度,曲线斜率表示了变化的速度

至于数值如何对应曲线就是另外一个话题了。

回归到之前的任务,似乎用这个最简单的CABasicAnimation就可以实现,实在是当时自己太不上心了。

二、再看看关键帧动画

关键帧动画CAKeyframeAnimation也继承CAPropertyAnimation,注意并不是基本动画的子类。

CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue);

CAKeyframeAnimation会使用一个NSArray保存这些数值

看一下别人的实例代码:

CAKeyframeAnimation *animaiton = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];  
NSArray *rotationVelues = @[@(M_PI_4), @(-M_PI_4), @(M_PI_4)];  
animaiton.values = rotationVelues;  
animation.rotationMode = kCAAnimationRotateAuto;  //方向
animaiton.duration = 3.0f;  
animation.keyTimes = @[@0.2 ,@0.8 ,@1];
animation.path = bezierPath.CGPath;
animaiton.repeatCount = HUGE_VALF;     //   #define    HUGE_VALF    1e50f  
[self.imageView.layer addAnimation:animaiton forKey:nil];  

KeyPath的意义两者是相同的,指明需要“动画化”的属性。

需要注意的和基本动画不同的概念:

1.values。 一个NSArray对象,里面的元素称为关键帧。

动画对象会在指定的时间(duration)内,依次显示数组中的每一个关键帧(也就是依次改变KeyPath属性值)

2.keyTimes。可以为对应的关键帧指定对应的时间点,取值范围0到1.0,默认关键帧时间平分

3.path。可以设置CGPathRef、CGMutablePath让图层按照路径轨迹移动,只对CALayer的anchorPoint和position起作用。如果设置了path,那么values将被忽略

另外,可以通过给view.layer添加CAShapeLayer设置path(猜测这样就不会和动画的values冲突?)

综上,CABasicAnimation可看做是只有2个关键帧的CAKeyframeAnimation

三、动画组和转场动画

1.动画组CAAnimationGroup

继承的是CAAnimation

可以保存一组动画对象,将CAAnimationGroup对象加入层后,组中所有动画对象可以同时并发运行

2.转场动画CATransition

CAAnimation的子类

能够为层提供移出屏幕和移入屏幕的动画效果

UINavigationController就是通过CATransition实现了将控制器的视图推入屏幕的动画效果

动画属性:(共有的duratio,timingFunction等属性)

type:动画过渡类型

subtype:动画过渡方向

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

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


其他概念补充

一、CALayer

关键需要理解UIView和CALayer的关系是平行关系,一对一关系

1.每个UIView都有一个CALayer实例的图层属性 view.layer

2.视图UIView的职责就是创建并管理图层CALayer

3.UIView和CALayer有着平行的层级关系,职责分离

还有不少内容,下一篇文章再记录


参考资料

https://www.jianshu.com/p/a53611d7eda5

https://www.jianshu.com/p/5df125e738b3

相关标签: 动画 iOS