简体   繁体   中英

For `UIView.animate`, is it possible to *chain* Swift Trailing Closures?

In Swift, I would like to have several calls to UIView.animate run in series. That is, when one animation finishes, then I would like another animation to continue after, and so on.

The call to UIView.animate has a Trailing Closure which I am currently using to make a second call to UIView.animate to occur.

The Problem is: I want to do N separate animations

From the Apple Documentation for UIView.animate

completion A block object to be executed when the animation sequence ends. This block has no return value and takes a single Boolean argument that indicates whether or not the animations actually finished before the completion handler was called. If the duration of the animation is 0, this block is performed at the beginning of the next run loop cycle. This parameter may be NULL.


Ideally, I would like to iterate over an array of animation duration s and use in the calls to animate()

For example,

Goal

Iterate over an array and apply those parameters for each animation

  • let duration = [3.0, 5.0, 10.0]
  • let alpha = [0.1, 0.5, 0.66]
  • Xcode Version 11.4.1 (11E503a)

What I've tried

Use a map to iterate, and hope that it works

  • Issue is that that only final animation occurs. So there is nothing in series
  • Research Q: Is it possible that I need to set a boolean in UIView that says animation occur in series?
let redBox = UIView()
redBox.backgroundColor = UIColor.red
self.view.addSubview(redBox)

let iterateToAnimate = duration.enumerated().map { (index, element) -> Double in
  print(index, element, duration[index])

  UIView.animate(withDuration: duration[index],  // set duration from the array
                 animations:  { () in
                   redBox.alpha = alpha[index]
                 }, completion:{(Bool)  in
                      print("red box has faded out")
  })
}

How to do one animation

let redBox = UIView()
redBox.backgroundColor = UIColor.red
self.view.addSubview(redBox)

// One iteration of Animation
UIView.animate(withDuration: 1,
               animations:  { () in
                 redBox.alpha = 0
               }, completion:{(Bool)  in
                    print("red box has faded out")
})

Ugly way to do chain two animate iterations (wish to avoid)

// two iterations of Animation, using a trailing closure
UIView.animate(withDuration: 1,
               animations:  { () in
                 redBox.alpha = 0
               }, completion:{(Bool)  in
                    print("red box has faded out")

}) { _ in  // after first animation finishes, call another in a trailing closure
  UIView.animate(withDuration: 1,
                 animations:  { () in
                   redBox.alpha = 0.75
                 }, completion:{(Bool)  in
                      print("red box has faded out")

  }) // 2nd animation
}

If the parameters are few and are known at compile time, the simplest way to construct chained animations is as the frames of a keyframe animation.

If the parameters are not known at compile time (eg your durations are going to arrive at runtime) or there are many of them and writing out the keyframe animation is too much trouble, then just put a single animation and its completion handler into a function and recurse. Simple example (adapt to your own purposes):

var duration = [3.0, 5.0, 10.0]
var alpha    = [0.1, 0.5, 0.66] as [CGFloat]

func doTheAnimation() {
    if duration.count > 0 {
        let dur = duration.removeFirst()
        let alp = alpha.removeFirst()
        UIView.animate(withDuration: dur, animations: {
            self.yellowView.alpha = alp
        }, completion: {_ in self.doTheAnimation()})
    }
}

you can use UIView.animateKeyframes

       UIView.animateKeyframes(withDuration: 18.0, delay: 0.0, options: [], animations: {
            UIView.addKeyframe(withRelativeStartTime: 3.0/15.0, relativeDuration: 3.0/15.0, animations: {
                self.redBox.alpha = 0
            })
            UIView.addKeyframe(withRelativeStartTime: 8.0/15.00, relativeDuration: 5.0/15.0, animations: {
               self.redBox.alpha = 0.75
            })
        }) { (completed) in
           print("completed")
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM