Skip to content

Latest commit

 

History

History

day-057

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

Day 57: Project 15: Animation, Part One

Follow along at https://www.hackingwithswift.com/100/57.

📒 Field Notes

This day covers the first part of Project 15: Animation in Hacking with Swift.

I previously created projects alongside Hacking with Swift in a separate repository, and you can find Project 15 here. Even better, though, I copied it over to Day 57's folder so I could extend it for 100 Days of Swift.

With that in mind, Day 57 focuses on several specific topics:

  • Preparing for action
  • Switch, case, animate: animate(withDuration:)
  • Transform: CGAffineTransform

Preparing for Action

After setting up our "Animate" button and the image to animate, our main challenge is structuring a way to cycle through different animations.

The word "cycle" provides a hint: Given that we're tracking a currentAnimationIndex alongside a total number of animations, we can increment the currentAnimationIndex around a modulus:

currentAnimationIndex = (currentAnimationIndex + 1) % 8

Here's that line as part of a larger triggerAnimation handler:

@IBAction func triggerAnimation(_ sender: UIButton) {
    triggerButton.alpha = 0.0

    UIView.animate(
        withDuration: animationDuration,
        delay: animationDelay,
        usingSpringWithDamping: 0.5,
        initialSpringVelocity: 5,
        options: [],
        animations: {
            self.runCurrentAnimation()
        },
        completion: { _ in
            self.triggerButton.alpha = 1.0
        }
    )

    currentAnimationIndex = (currentAnimationIndex + 1) % 8
}

Switch, case, animate: animate(withDuration:)

So that runCurrentAnimation function.... This is where we can actually switch on the currentAnimationIndex and choose a set of operations to perform during the lifetime of the UIView.animate animation:

func runCurrentAnimation() {
    switch currentAnimationIndex {
    case 1, 3, 5:
        imageView.transform = .identity
    case 0:
        imageView.transform = CGAffineTransform(scaleX: 2, y: 2)
    case 2:
        imageView.transform = CGAffineTransform(translationX: -(view.center.x / 2), y: -(view.center.y / 2))
    case 4:
        imageView.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
    case 6:
        imageView.alpha = 0.1
        imageView.backgroundColor = UIColor.purple
    case 7:
        imageView.alpha = 1.0
        imageView.backgroundColor = UIColor.clear
    default:
        preconditionFailure("Current animation index is out of range")
    }
}

Transform: CGAffineTransform

CGAffineTransform allows us to manipulate an affine transformation matrix belonging to a particular UIView.

Because the raw process of that can be a bit mathematically... intricate... CGAffineTransform also provides several higher-level initializers that allow us to be more declarative and high-level:

imageView.transform = CGAffineTransform(scaleX: 2, y: 2)
imageView.transform = CGAffineTransform(translationX: -(view.center.x / 2), y: -(view.center.y / 2))
imageView.transform = CGAffineTransform(rotationAngle: CGFloat.pi)

Hand-in-hand with making transforms that alter an object, we can use CGAffineTransform.identity to reset the matrix to the object's original state:

imageView.transform = .identity

🔗 Additional/Related Links