2.Popping笔记--Decay Animation

Popping笔记。Github上搜索"Popping"即可下载源代码。

Decay Animation


首先分析动画。

1.屏幕中心一个圆。

2.拖动圆,圆会运动并逐渐减速直到停止。

3.在圆运动的过程中,如果点击圆,圆会立即停到点击的地方。

4.如果圆碰到屏幕边缘,会立即弹回到屏幕中点,并且感觉有一些弹性。

这个动画很简单,我们来看源代码。

打开DecayViewController.m

addDragView方法的主要是构造我们的圆,并且设置点击圆时候的处理方法和进行pan手势所使用的方法。有一点需要注意的是dragView是一个UIControl,如果用的是UIView,则没有addTarget:action:这个方法。UIControl是UIView的子类,实现了更多的功能,比如刚才我们所说的。

touchDown:方法很简单,如果用户点击了圆,那么就移除这个圆的图层的所有pop动画,这也是我们在最开始时候分析的第3点的原因。

接下来看handlePan:方法。我们想一下,这个方法肯定是想要让这个圆跟着我们的手指(鼠标)走,那么圆的位置该如何计算呢?

很简单,圆的位置 = 圆现在的位置 + 手指在屏幕上滑动的距离。

所以首先我们得到手指滑动的距离,recognizer有很方便的方法返回一个CGPoint的值,分别代表x,y方向上平移的距离。有了手指滑动的距离,我们就可以设置圆的位置了。recognizer有一个view的属性可以得到它所监听的对象,也就是dragView。我们将drageView的中点设置成其原来的位置+平移的距离,就像刚才说的那样。

注意:

[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];

这行很重要。在每次移动的时候我们都要将recognizer的x,y方向上的translation设置成0,否则在下一次平移的时候translation就会叠加,我们的圆会直接飞出屏幕,因为这次移动不仅包含了这次平移的距离,还包含了以前平移的距离。

可以注意到如果我们手指一直在圆上,并不会出现减速效果,只有手指离开圆,即结束了pan的手势,那么圆开始减速运动。接下来这行代码就是解释这一现象的:判断recognizer的状态,如果已经结束(即手指离开了屏幕,不再拖动圆),那么给圆加上一个POPDecayAnimation动画。

if(recognizer.state == UIGestureRecognizerStateEnded) {
    CGPoint velocity = [recognizer velocityInView:self.view];
    POPDecayAnimation *positionAnimation = [POPDecayAnimation animationWithPropertyNamed:kPOPLayerPosition];
    positionAnimation.delegate = self;
    positionAnimation.velocity = [NSValue valueWithCGPoint:velocity];
    [recognizer.view.layer pop_addAnimation:positionAnimation forKey:@"layerPositionAnimation"];
}

首先得到手指在屏幕上的移动速度,接着创建POPDecayAnimation动画,设置其速度为刚才得到的速度。那么设置动画的delegate是因为什么呢?

看看我们在开始的分析的第4点你可能就会明白了。我们需要判断每次移动的时候圆是不是超出边界了。POP为我们提供了一个代理方法:

- (void)pop_animationDidApply:(POPDecayAnimation *)anim

动画的每一帧都会调用这个方法,这也正是我们需要的,因为我们需要时时刻刻都注意圆是否超出边界了。

- (void)pop_animationDidApply:(POPDecayAnimation *)anim
{
    BOOL isDragViewOutsideOfSuperView = !CGRectContainsRect(self.view.frame, self.dragView.frame);
    if (isDragViewOutsideOfSuperView) {
        CGPoint currentVelocity = [anim.velocity CGPointValue];
        CGPoint velocity = CGPointMake(currentVelocity.x, -currentVelocity.y);
        POPSpringAnimation *positionAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPosition];
        positionAnimation.velocity = [NSValue valueWithCGPoint:velocity];
        positionAnimation.toValue = [NSValue valueWithCGPoint:self.view.center];
        [self.dragView.layer pop_addAnimation:positionAnimation forKey:@"layerPositionAnimation"];
    }
}

在动画的每一帧,我们需要判断是否出界。

CGRectContainsRect(rect1,rect2)顾名思义,判断rect2是否在rect1中,返回一个BOOL值。
一旦dragView不在self.view中了,我们就让dragView回到view的中点,具体做法是:

得到currentVelocity(就是最开始手指移动的速度?),接着得到velocity:

    CGPoint velocity = CGPointMake(currentVelocity.x, -currentVelocity.y);

这句我也不是很懂,为什么要这样做有没有朋友可以指教一下?3QQQQ

接着创建POPSpringAnimation,设置velocity和toValue。

这里有一点需要注意,在我自己写代码的时候因为这个马虎浪费了很多时间。。那就是我们刚才创建的decay animation的key和现在创建的spring animation的key需要保持一致。其实道理很简单:我们首先创建了decay animation,我们希望圆一碰壁就弹回,即使用spring animation,但是有的时候decay animation还未结束就已经碰壁,如果这两个key不一样,则spring animation需要等待decay animation结束才能执行,这也是为什么圆会出屏幕一段时间然后弹回屏幕中点。正确的做法是我们将两者的key设置成相同的,我的理解是:首先执行decay animation,一旦圆碰壁了,我们添加spring animation,因为两者是相同的key意思就是在原来动画的基础上变换成新的动画,所以圆会马上回到中点。而不是相同的key则相当于创建了两个完全不同的动画,那么就需要一个结束另一个才能执行,所以圆会一直等到decay结束才能spring。


在这个例子之前我对velocity和toValue属性并不是很理解,现在有了一些新的理解:

并不是每一个动画都需要toValue,比如说我们这个decay的例子,我们不需要设置toValue,只需要给decay animation一个velocity,它会自己根据这个速度来减速。

同样的,在我们第一个例子shake button这个方法里面,我们创建了一个spring animation,没有设置其toValue,而是给这个动画一个velocity让其根据这个速度移动。

所以我的理解是:toValue是我们给定一个目的地,是精确的。而velocity是我们给定一个速度让其根据这个速度走,而究竟在哪一点停下来(decay animation),是远是近(spring animation,时间不变,速度越快走的越远),都要根据这个velocity。如果既设置toValue又设置velocity,则是到达目的地的快慢不同。这只是自己的理解,可能有不准确的地方,希望不吝赐教。

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

推荐阅读更多精彩内容

  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥ios动画全貌。在这里你可以看...
    每天刷两次牙阅读 8,471评论 6 30
  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看...
    F麦子阅读 5,104评论 5 13
  • 目录 ** UIView 动画 ** ** Core Animation ** ** FaceBook POP动画...
    方向_4d0d阅读 1,594评论 0 3
  • 书写的很好,翻译的也棒!感谢译者,感谢感谢! iOS-Core-Animation-Advanced-Techni...
    钱嘘嘘阅读 2,293评论 0 6
  • 我们写的应用程序往往都不是静态的,因为它们需要适应用户的需求以及为执行各种任务而改变状态。 在这些状态之间转换时,...
    sunmumu1222阅读 696评论 0 2