2016-05-14 57 views
3

SITUTATION:如何在連續的repeatForever中鏈接Facebook流行動畫?

我創建了一個脈動動畫,它的工作原理。

使用repeatForever屬性,我能夠使其連續,因爲我想。

但仍然有一個問題,我做了很多研究後無法修復。


說明:

唯一的問題是,我不知道如何添加一個動畫,使圖像回到它的原始尺寸再次搏動之前。

我面臨的挑戰在於如果我在另一個之後聲明它,它將不會被調用,因爲它不會包含在repeatForever循環中。

因此,我現在所擁有的動畫並不平滑,因爲一旦它完成,圖像會在重複之前立即回到原始大小。


會發生什麼:

1)圖像脈動電流大小THX的1.2〜動畫。

THIS IS NOT SMOOTH:

2)動畫完成在1.2和圖像即刻 「翹曲」 回1.0

3)動畫重演。圖像再次跳動到1.2。


問題:我怎樣才能改變我的pulsatingAnimation讓我的形象可以追溯到它的原始尺寸比較順利地再次脈動過嗎?


CODE:

import Foundation 
import pop 

class AnimationEngine { 

    func pulsate(object: UIImageView) { 
     let pulsateAnim = POPSpringAnimation(propertyNamed: kPOPLayerScaleXY) 
     pulsateAnim.velocity = NSValue(CGSize: CGSizeMake(0.1, 0.1)) 
     pulsateAnim.toValue = NSValue(CGSize: CGSizeMake(1.2, 1.2)) 
     pulsateAnim.springBounciness = 18 
     pulsateAnim.dynamicsFriction = 20 
     pulsateAnim.springSpeed = 1.0 
     pulsateAnim.repeatForever = true 
     // pulsateAnim.autoreverses = true 
     object.layer.pop_addAnimation(pulsateAnim, forKey: "layerScaleSpringAnimation") 
    } 
} 
+1

@AlessandroOrnano偉大的thx :) Upvote – Coder1000

+0

'autoreverses'設置爲'true'會發生什麼?動畫能夠正常工作,但不會重複?是對的嗎? – Sulthan

+0

@Sulthan不完全是,當autoreverses設置爲true時,動畫反向運行。這意味着它會隨着我想變大而跳動,然後它會回到原來的大小(我不想這樣,我想它會跳動,然後再順利地返回到原來的大小,而不會再次脈動)。但動畫無限重複,如想:) – Coder1000

回答

3

我找到了解決方案。

SOLUTION:

func pulsate(object: UIImageView) { 
    let pulsateAnim = POPSpringAnimation(propertyNamed: kPOPLayerScaleXY) 
    let returnToSizeAnim = POPBasicAnimation(propertyNamed: kPOPLayerScaleXY) 

    object.layer.pop_addAnimation(pulsateAnim, forKey: "layerScaleSpringAnimation") 
    pulsateAnim.velocity = NSValue(CGSize: CGSizeMake(0.1, 0.1)) 
    pulsateAnim.toValue = NSValue(CGSize: CGSizeMake(1.2, 1.2)) 
    pulsateAnim.springBounciness = 30 
    pulsateAnim.dynamicsFriction = 20 
    pulsateAnim.springSpeed = 1.0 
    pulsateAnim.completionBlock = {(animation, finished) in 
     object.layer.pop_addAnimation(returnToSizeAnim, forKey: "layerScaleSpringAnimation") 
    } 
    returnToSizeAnim.toValue = NSValue(CGSize: CGSizeMake(1.0, 1.0)) 
    returnToSizeAnim.duration = 0.5 
    returnToSizeAnim.completionBlock = {(animation, finished) in 
     object.layer.pop_addAnimation(pulsateAnim, forKey: "layerScaleSpringAnimation") 
    } 
} 

func pulsate2(object: UIImageView) { 
    let pulsateAnim = POPSpringAnimation(propertyNamed: kPOPLayerScaleXY) 
    let returnToSizeAnim = POPBasicAnimation(propertyNamed: kPOPLayerScaleXY) 

    object.layer.pop_addAnimation(pulsateAnim, forKey: "layerScaleSpringAnimation") 
    pulsateAnim.velocity = NSValue(CGSize: CGSizeMake(0.1, 0.1)) 
    pulsateAnim.toValue = NSValue(CGSize: CGSizeMake(1.2, 1.2)) 
    pulsateAnim.springBounciness = 30 
    pulsateAnim.dynamicsFriction = 20 
    pulsateAnim.springSpeed = 1.0 
    pulsateAnim.completionBlock = {(animation, finished) in 
     object.layer.pop_addAnimation(returnToSizeAnim, forKey: "layerScaleSpringAnimation") 
    } 
    returnToSizeAnim.toValue = NSValue(CGSize: CGSizeMake(1.0, 1.0)) 
    returnToSizeAnim.duration = 0.5 
    returnToSizeAnim.completionBlock = {(animation, finished) in 
     object.layer.pop_addAnimation(pulsateAnim, forKey: "layerScaleSpringAnimation") 
    } 
} 

N.B:

我需要聲明一個搏動功能我想使用它的每個對象。如果我不這樣做,第二次調用該函數時,它將無法正常工作,因爲動畫的一個實例已經在運行。

1

我不知道Facebook pop,所以我只談論的分析和邏輯如何實現此功能(脈衝效應)

,因爲我已經寫在評論中,你想要做的事情看起來好像在SpriteKit中發生了很多次,你要做一個特定的動畫(SKAction),必須建立一系列的動作。

只是爲了讓一個SpriteKit例子,這是我怎麼做才能讓一個特定的脈衝效應:

let titleForward = runTitleForward() 
let wait = SKAction.waitForDuration(5.0) 
let titleBackward = runTitleBackward() 
let titleAnim = SKAction.repeatActionForever((SKAction.sequence([titleForward, wait, titleBackward,wait ]))) 
title.runAction(titleAnim, withKey:"titleAnimation") 

func runTitleForward()-> SKAction { 
     let atlascTexturesArray = self.myManager.atlascTexturesDictionary["title-anim"] 
     let texturesAction = SKAction.animateWithTextures(atlascTexturesArray!,timePerFrame: 0.09)   
     return texturesAction 
    } 

func runTitleBackward()-> SKAction { 
    let texturesAction = runTitleForward() 
    let texturesReverseAction = SKAction.reversedAction(texturesAction) 
    return texturesReverseAction() 
} 

希望大家幫做同樣的事情在UIKit

UPDATE:(我沒有測試它..)

func delayAnimation(duration:NSTimeInterval)-> CABasicAnimation { 
    let animation : CABasicAnimation = CABasicAnimation(keyPath: "opacity"); 
    animation.delegate = self 
    animation.fromValue = 1 
    animation.toValue = 1 // fake animation, just to obtain duration delay.. 
    animation.duration = duration 
    return animation 
} 

func pulseElements() -> (POPSpringAnimation,POPSpringAnimation) { 

     // zoom in 
     let pulsateInAnim = POPSpringAnimation(propertyNamed: kPOPLayerScaleXY) 
     pulsateInAnim.velocity = NSValue(CGSize: CGSizeMake(0.1, 0.1)) 
     pulsateInAnim.toValue = NSValue(CGSize: CGSizeMake(1.2, 1.2)) 
     pulsateInAnim.springBounciness = 18 
     pulsateInAnim.dynamicsFriction = 20 
     pulsateInAnim.springSpeed = 1.0 

     // zoom out 
     let pulsateOutAnim = POPSpringAnimation(propertyNamed: kPOPLayerScaleXY) 
     ... 

     return (pulsateInAnim,pulsateOutAnim) 
} 

func pulseAnimation() { 
    let (pulsateInAnim,pulsateOutAnim) = pulseElements() 
    let wait = delayAnimation(1.0) 
    var pulseAnimationGroup: CAAnimationGroup = CAAnimationGroup() 
    pulseAnimationGroup.animations = [pulsateInAnim, wait, pulsateOutAnim, wait] 
    pulseAnimationGroup.duration = 0.5 
    pulseAnimationGroup.repeatCount = Float.infinity 
    object.layer.addAnimation(pulseAnimationGroup, forKey: layerScaleSpringAnimation) 
} 
+1

可悲的是,我沒有能夠重現這在Facebook流行,但它肯定幫助,謝謝! – Coder1000

+0

這很難,是否可以在塊中使用POPSpringAnimation?完成按順序製作兩個動畫。然後,有一個方法,如:animationWithanimation創建一個新的動畫與序列repeatoverver它... –

+0

我想到了完成塊,但我不知道如何創建一個新的動畫序列,然後重複它:( – Coder1000

1

我是一個巨大的ReactiveCocoa書呆子,所以我周圍建一個POPAnimation類,所以我可以在一個功能更強大的方式處理動畫。

import Foundation 
import ReactiveCocoa 
import pop 
import Result 

/** 
`UIView` wrapper for performing reactive-based pop animations. 
*/ 
public struct ReactivePOPView<View: UIView> { 

    /// View object 
    private weak var view: View? 
    /// `SignalProducer` object when the wrapper is about to deallocate. 
    private let willDealloc: SignalProducer<Void, NoError> 

    /// Wrapper on the view property. 
    private var animator: View? { return self.view } 

    /** 
    Create an animation wrapper with a view. 

    - parameter view: `UIView` object. 
    */ 
    public init(_ view: View) { 
     self.view = view 
     self.willDealloc = view 
      .willDeallocSignalProducer() 
     } 
} 

/** 
Binds a `Signal` that emits an animation object to a `ReactivePOPView`. 

- parameter view: `ReactivePOPView` object. 
- parameter signal: `Signal` object. 

- returns: `Disposable` object. 
*/ 
public func <~ <T, Animation: POPAnimation>(view: ReactivePOPView<T>, signal: Signal<Animation, NoError>) -> Disposable { 
    let disposable = CompositeDisposable() 
    let viewDisposable = view.willDealloc.startWithCompleted { 
     disposable.dispose() 
    } 
    disposable.addDisposable(viewDisposable) 

    let signalDisposable = signal.observe(Observer(next: { 
     view.animator?.pop_addAnimation($0, forKey: $0.name ?? "") 

    }, completed: { 
     disposable.dispose() 
    })) 
    disposable.addDisposable(signalDisposable) 
    return disposable 
} 

/** 
Binds a `SignalProducer` that emits an animation object to a `ReactivePOPView`. 

- parameter view:  `ReactivePOPView` object. 
- parameter producer: `SignalProducer` object. 

- returns: `Disposable` object. 
*/ 
public func <~ <T, Animation: POPAnimation>(view: ReactivePOPView<T>, producer: SignalProducer<Animation, NoError>) -> Disposable { 
    var disposable: Disposable! 
    producer.startWithSignal { signal, signalDisposable in 
     view <~ signal 
     disposable = signalDisposable 

     view.willDealloc.startWithCompleted { 
      signalDisposable.dispose() 
     } 
    } 
    return disposable 
} 

/** 
Bind a reactive animation property to a `ReactivePOPView` property. 

- parameter destinationProperty: `ReactivePOPView` property. 
- parameter sourceProperty:  Animation property. 

- returns: `Disposable` object. 
*/ 
public func <~ <T, P: PropertyType where P.Value == POPAnimation>(destinationProperty: ReactivePOPView<T>, sourceProperty: P) -> Disposable { 
    return destinationProperty <~ sourceProperty.producer 
} 

有了這個類,你可以做這樣的事情:

ReactivePOPView<UIButton>(self.loginButton) <~ self.someSignal.signal 
.flatMap(.Concat) { _ in SignalProducer<POPBasicAnimation, NoError> in 
    let animation ... 
    // construct animation here 
    return SignalProducer(value: animation) 
} 
.repeat(0) 

我也有約束的包裝類,如果你想要的。

+0

這很好,但我可以一次傳遞2個動畫,如:'return SignalProducer(value:animation1,animation2)'? – Coder1000

+0

確實沒有辦法只使用facebook Pop已經提供的功能來做什麼? – Coder1000

+0

當然,您可以創建兩個單獨的動畫信號並執行SignalProducer(values:[firstAnimationProducer,secondAnimationProducer])。flatten(.Merge)''這可以在動畫觸發時應用這兩個動畫,或者你可以執行'SignalProducer(values:[someTrigger.flatMap(.Latest){_ in animationSignal},otherTrigger.flatMap(.L atest){_ in secondAnimation}])。flatten(.Merge)' 可能有,我不知道。我不是pop的專家,這只是我使用動畫和反應可可來簡化的一種方式。 – barndog