iOS进阶之编写弹性动画

前言

之前在iOS开发干货 第1期中提到过一个挺有意思的数字转变动画NumberMorphView , 如下图:

NumberMorphView
NumberMorphView

我将通过几篇文章对这个开源库做一些分析,当然,这篇文章不会对它做全面的解析,而是利用这个库的一些技术概念来做一些简单的示例,也算是一个引子,后面会抽时间再写一篇对这个库的代码分析,敬请期待。

要做些什么

我们将会使用CADisplayLink + CAShapeLayer + UIBezierPath结合制作一个毫秒级的画圆动画,不同的是,这个动画具有弹性效果,下面先来看看制作的效果:

效果预览

开始

准备工作

  1. 先新建一个Single View Application项目,在项目中添加类RRCircleAnimationView,继承于UIView。
  2. 打开Main.storyboard,将唯一的一个ViewController的view custom class修改为RRCircleAnimationView。
    至此,准备工作已经完成。

动手来画个圆

先来个简单任务,我们来实现画圆动画。

第一步,为RRCircleAnimationView添加属性:

@implementation RRCircleAnimationView
{
    CADisplayLink *_displayLink; // CADisplayLink可以确保系统渲染每一帧的时候我们的方法都被调用, 从而保证了动画的流畅性,毫秒级动画就靠他。
    UIBezierPath *_path; // 用于创建基于矢量的路径
    CGPoint _beginPoint; // 开始触摸位置
    CGPoint _endPoint;  // 触摸结束的位置
    CAShapeLayer *_shapeLayer; // 可以结合UIBezierPath进行绘画

}

接着初始化实例变量,由于我们用的是storyboard进行加载,所以可以在awakeFromNib方法里面初始化

// 注意这里我们是直接从xib加载当前view。
- (void)awakeFromNib
{
    _shapeLayer = [CAShapeLayer layer];
    [self.layer addSublayer:_shapeLayer];
    _shapeLayer.fillColor = [UIColor colorWithRed:0.400 green:0.400 blue:1.000 alpha:1.000].CGColor;
    _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateFrame)];
    [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}

接下来实现上面CADisplayLink要不停调用的updateFrame方法,我们在此方法内不断地画圆。

- (void)updateFrame {

    // 画圆
    _path = [UIBezierPath bezierPathWithArcCenter:_beginPoint radius:[self getRadius] startAngle:0 endAngle:M_PI*2 clockwise:YES];
    _shapeLayer.path = _path.CGPath;

}

上面我们用开始触摸的点的位置作为圆心的位置,再根据特定的半径进行绘制一个圆,这个半径是根据我们触摸的开始点和结束点进行计算出来的,开始触摸点到结束点的距离就是这个圆的半径。

我们先把触摸的起始和结束点给找到:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];
    _beginPoint = point;
    _endPoint = point;
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];
    _endPoint = point;
}


最后计算用上我们中学的数学知识,根据两点坐标距离公式

两点坐标距离公式

可以得到我们起始和结束两点的距离,也就是圆的半径是:

- (CGFloat)getRadius
{
    CGFloat result = sqrt(pow(_endPoint.x - _beginPoint.x, 2) + pow(_endPoint.y - _beginPoint.y, 2));

    return result;
}

到这里画圆动画完成。

加入弹性效果

上面只是的画圆动画看起来是没什么问题了,不过总感觉缺少动感,接下来我们来帮他加入些活力!

  1. 添加一下成员变量到RRCircleAnimationView类中。

        BOOL _isTouchEnd; // 触摸结束标志
        int _currentFrame; // 当前的帧数
    
  2. - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event方法内添加以下代码:

        _isTouchEnd = NO; //重置触摸状态
        _currentFrame = 1; //重置当前的帧数
    
  3. 添加以下方法:

    - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        _isTouchEnd = YES; //触摸结束,更新触摸状态
        
    }
    
  4. 将方法- (CGFloat)getRadius修改如下:

    - (CGFloat)getRadius
    {
        CGFloat result = sqrt(pow(_endPoint.x-_beginPoint.x, 2)+pow(_endPoint.y-_beginPoint.y, 2));
        if (_isTouchEnd) {
            CGFloat animationDuration = 1.0; // 弹簧动画持续的时间
            int maxFrames = animationDuration / _displayLink.duration;
            _currentFrame++;
    
                if (_currentFrame <= maxFrames) {
                    CGFloat factor = [self getSpringInterpolation:(CGFloat)(_currentFrame) / (CGFloat)(maxFrames)]; //根据公式计算出弹簧因子
                    return MAX_RADIUS + (result - MAX_RADIUS) * factor; // 根据弹簧因子计算当前帧的圆半径
                }else {
                    return MAX_RADIUS;
                }
    
        }
        return result;
    }
    
  5. 最后加入神奇的公式:

    - (CGFloat)getSpringInterpolation:(CGFloat)x
    {
        CGFloat tension = 0.3; // 张力系数
        return pow(2, -10 * x) * sin((x - tension / 4) * (2 * M_PI) / tension);
    }
    

这个公式用数学符号表达出来是:

Math

可以用Mac OS X自带的软件叫Grapher画出此函数的的图像,如下图:

Grapher

这个函数的作用其实就是通过x值,也就是当前帧数除以允许的最大帧数。

(CGFloat)(_currentFrame) / (CGFloat)(maxFrames)

因此,x的值的范围也就是(0, 1]。

我们所要的动画效果是把圆拉大到超过或者小于设定的目标半径MAX_RADIUS时,需要一个弹性动画逐渐回到设定好的目标半径。

回头再看一下实时计算动画半径的公式:

MAX_RADIUS + (result - MAX_RADIUS) * factor

为了让x = 1的时候,半径 = MAX_RADIUS,所以这时factor就应该为0,也就是f(1) = 0。

再看看刚才的函数图像,在x = 0到1之前振动,随着x的增加振幅逐渐减少,当x = 1的时候,y值为0。

最后

这篇文章讲述了如何自己实现具有弹性的帧动画,如果能理解好这种动画制作原理,对动画效果开发是很有帮助的,后面有时间会继续写其他的一些动画制作的方法,实现更多的动画效果。

差点忘了说了,目前这个动画已经放到github上面,传送门:RRongAnimation

RRongAnimation
RRongAnimation

The End

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • http://www.jianshu.com/p/cf9f600a5342
    sfandy阅读 245评论 0 0
  • 前言 本文只要描述了iOS中的Core Animation(核心动画:隐式动画、显示动画)、贝塞尔曲线、UIVie...
    GitHubPorter阅读 3,600评论 7 11
  • Core Animation Core Animation,中文翻译为核心动画,它是一组非常强大的动画处理API,...
    45b645c5912e阅读 3,013评论 0 21
  • Android动画的分类:三种,属性动画,补间动画,帧动画 补间动画:缩放,平移,旋转,透明度 API:Anima...
    EvanPoison阅读 202评论 0 0
  • 台词“直白”,一般人对话不会有这样的思考吧。那是压抑了很久,想表达好多东西。才会对一个人说这样的台词,富有思想,当...
    RingRun阅读 304评论 0 0