Oleg Korban
Oleg Korban

Reputation: 269

Functions chain with delays in swift

I'm wondering how it is possible to chain a sequence of UIView.animationWithDuration:completion: functions to perform each next function from completion closure of previous animationWithDuration. So I should have something like:

finalAnimation <<< animationB <<< animationA <<< initialValues()

It's easy to chain them if functions doesn't have any time delay inside. Also it's easy to build a queue of animations with a shared object that contains queue items. But it's not clear how to build such queue without sharing anything but just chaining animationWithDuration:completion: Thanks for your advice

Upvotes: 2

Views: 664

Answers (4)

Duncan C
Duncan C

Reputation: 131418

I agree with @NRitH that keyframe animations are a good way to go.

Another option is to write a method that calls itself from the completion handler. Something like this:

var step = 3;

func animate()
{
  UIView.animateWithDuration: 1.0,
    delay: 1.0,
    options: 0,
    animations: ^
    {
       switch step:
       {
         case 3:
           //1st animation
         case 2:
           //2nd animation
         case 1:
           //3rd animation
         default:
           //we're done
       }
    },
    completion: ^
    {
      (finished) in
      step--
      if finished && step > 0
      {
         animate()
      }
    }
}

(Syntax may not be perfect. I've been working in Objective-C for the past month or so so my Swift has gotten a tad rusty.)

EDIT:

I just realized that you wanted to add delay between the animations. I edited my code to show how to do that.

I put in a fixed delay of 1 second between steps. If you want variable delay, you'd need to create an array of delay values.

Upvotes: 1

Basheer_CAD
Basheer_CAD

Reputation: 4919

You can not chain with animation, chaining requires the function to return optional type fun1()?.func2()?.func3() . This is not achievable since animateWithDuraion: return immediately. You can use dispatch_semaphore to wait for completion block but it is not recommended since your animation should not not block the main thread

here is my suggestion:

you can do something like this

func myAnimation(duration: NSTimeInterval, animation:() -> Void, onFinish: () -> Void) {

    UIView.animateWithDuration(duration, animations: { () -> Void in
        animation()
    }) { (finished: Bool) -> Void in
        onFinish()
    }
}

and then

myAnimation(0.0, { animation in

        }) { completion in

        myAnimation(0.0, { animation in

        }, { completion in
            myAnimation(0.0, { animation in

            }, { completion in

            })
        })
    }

Upvotes: 1

NRitH
NRitH

Reputation: 13893

DON'T nest animations. What you want is animateKeyframesWithDuration(_:delay:options:animations:completion:), which allows you to chain animations together in a much cleaner way.

See also http://commandshift.co.uk/blog/2014/04/01/stop-nesting-animation-blocks/

Upvotes: 1

TheNiers
TheNiers

Reputation: 237

I came across this library which might be interesting for you. It has a section in its documentation about chaining animations.

https://github.com/MengTo/Spring

Upvotes: 1

Related Questions