2

NO UIVIEW ANIMATIONS, I'M LEARNING CORE ANIMATION

When I run this code, the top image is not on the screen. Then 4 seconds later, it reappears and does as expected. Not sure why. What I want is for the top image to be on the screen when the app launches, and then 4 seconds later for the top image to move up and out of the screen.

    @IBOutlet var top: UIImageView!

    override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    let openTop = CABasicAnimation(keyPath: "position.y")
    openTop.fromValue = self.top.frame.origin.y
    openTop.toValue = -self.view.bounds.size.height
    openTop.duration = 1.0
    openTop.beginTime = CACurrentMediaTime() + 4
    self.top.layer.addAnimation(openTop, forKey: nil)
    self.top.layer.position.y = -self.view.bounds.size.height

}

Any thoughts?

JEL
  • 1,540
  • 4
  • 23
  • 51

2 Answers2

0

so you want the image to be on-screen at the start, and then 4 seconds later to fly off the top? You can do this by grouping animations together

override func viewDidAppear(animated: Bool)
{
    super.viewDidAppear(animated)

    // keep a track of where we want it to be
    let y = self.top.layer.position.y

    // move it out of the way - this where it will end up after the animation
    self.top.layer.position.y = -self.view.bounds.size.height

    // do nothing, other than display the image for 4 seconds
    let doNothing = CABasicAnimation(keyPath: "position.y")
    doNothing.fromValue = y
    doNothing.toValue = y
    doNothing.duration = 4.0

    // zip it away
    let openTop = CABasicAnimation(keyPath: "position.y")
    openTop.fromValue = y
    openTop.toValue = -self.view.bounds.size.height
    openTop.duration = 1.0
    openTop.beginTime = doNothing.beginTime + doNothing.duration

    // create the group
    let group = CAAnimationGroup()
    group.duration = 5.01
    group.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
    group.removedOnCompletion = false
    group.fillMode = kCAFillModeForwards
    group.animations = [doNothing, openTop]

    self.top.layer.addAnimation(group, forKey: nil)
}
Russell
  • 5,436
  • 2
  • 19
  • 27
  • If I do that, the animation works, but when the animation ends, the image goes back to where it started. The image just appears back at where it started. Any other suggestions? – JEL Mar 03 '16 at 18:17
  • good point - you could use a group of animations (just two in this case) Start with `top` off-screen, bring it on-screen VERY fast, so it doesn't look like an animation, and the slowly remove it. Here's a description of grouping animations http://stackoverflow.com/questions/11737658/how-to-chain-different-caanimation-in-an-ios-application and I will update the answer to show what I mean – Russell Mar 03 '16 at 18:21
  • Ok thanks looking forward to your updated answer --- I'm still very new to core animation so hard for me to implement groups on my own – JEL Mar 03 '16 at 18:27
  • You can simply position your image off the top of the screen, _then_ add an animation that moves it from on screen to off – nielsbot Mar 03 '16 at 18:51
  • I have simplified the answer above, based on @nielsbot's comment – Russell Mar 03 '16 at 21:41
  • You might also try without the group? Use a single animation with _beginTime_ set to `CAMediaTimeCurrent() + 4.0` and `fillMode = "both"`. But I'd have to try it to be sure... – nielsbot Mar 03 '16 at 22:08
  • But pretty sure you can make this work w/o the "doNothing" animation – nielsbot Mar 03 '16 at 22:09
  • @Russell This looks complicated for such a basic animation. It works but is this the only way to do it? I will accept the answer, just asking. – JEL Mar 04 '16 at 19:07
  • @nielsbot Can you show how you would simplify this answer? – JEL Mar 04 '16 at 19:08
  • I tried as above, but without `doNothing` and the image only appeared after 4 seconds, and then disappeared, and if the image starts on-screen, then it flies off, and then re-appears – Russell Mar 04 '16 at 20:33
0

Here's what I came up with:

let l = top.layer!
let startingPosition = l.position
l.position = CGPointMake( CGRectGetMidX( self.view.bounds ), -l.frame.height * 0.5 )

l.addAnimation({
    let anim = CABasicAnimation( keyPath: "position" )
    anim.fromValue = NSValue( CGPoint:startingPosition )
    anim.beginTime = CACurrentMediaTime() + 4.0
    anim.fillMode = kCAFillModeBoth
    return anim
}(), forKey: nil)
nielsbot
  • 15,922
  • 4
  • 48
  • 73
  • I accepted this answer because its the simplest here. Can you explain why you have to move the layers position first with `l.position = CGPointMake( CGRectGetMidX( self.view.bounds ), -l.frame.height * 0.5 )`? The way I was doing it was calling soothing similar to this after I added the animation but you did it before adding the animation. Why is this the way to do it? – JEL Mar 07 '16 at 00:08
  • It think it's less code that way. You also don't have to worry about removing the animation later. – nielsbot Mar 07 '16 at 02:36