Skip to content

Instantly share code, notes, and snippets.

@mathewsanders
Last active March 13, 2017 21:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mathewsanders/3891469557d564d003e66efefac8b260 to your computer and use it in GitHub Desktop.
Save mathewsanders/3891469557d564d003e66efefac8b260 to your computer and use it in GitHub Desktop.
Example of exploring animation in a playground with use of UISlider to scrub animation.
import UIKit
import PlaygroundSupport
let containerView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
containerView.backgroundColor = .white
// Show the container view in the Assistant Editor
PlaygroundPage.current.liveView = containerView
// transformations for the dots to be pushed to either left or right of capsule
let offstageLeft = CGAffineTransform(translationX: -100, y: 0)
let offstageRight = CGAffineTransform(translationX: 100, y: 0)
let capsuleFrameWide = CGRect(origin: .zero, size: CGSize(width: 100, height: 50))
let capsuleFrameNarrow = CGRect(origin: .zero, size: CGSize(width: 50, height: 50))
// create view to hold the dots ('capsule')
let capsule = UIView(frame: capsuleFrameWide)
capsule.backgroundColor = #colorLiteral(red: 0.921431005, green: 0.9214526415, blue: 0.9214410186, alpha: 1)
capsule.layer.cornerRadius = 25
capsule.clipsToBounds = true
containerView.addSubview(capsule)
// create three dots
let capsuleDots = [UIView(), UIView(), UIView()]
// set common properties for the dots
capsuleDots.forEach({ dot in
dot.bounds = CGRect(origin: .zero, size: CGSize(width: 10, height: 10))
dot.alpha = 0.0
dot.transform = offstageLeft
dot.layer.cornerRadius = 5
dot.backgroundColor = #colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1)
capsule.addSubview(dot)
})
// position dots center, left of center, and right of center
capsuleDots[0].center = capsule.center
capsuleDots[1].center = capsule.center.applying(CGAffineTransform(translationX: 20, y: 0))
capsuleDots[2].center = capsule.center.applying(CGAffineTransform(translationX: -20, y: 0))
// position the capsule in center of container view
capsule.center = containerView.center
// decrease the size of the capsure for the
capsule.bounds = capsuleFrameNarrow
let animator = UIViewPropertyAnimator(duration: 2, curve: .easeIn)
// the actual animation occurs in 4 steps
animator.addAnimations {
UIView.animateKeyframes(withDuration: 2, delay: 0, options: [.calculationModeLinear], animations: {
// step 1: make the capsule grow to large size
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.1) {
capsule.bounds = capsuleFrameWide
}
// step 2: move the dots to their default positions, and fade in
UIView.addKeyframe(withRelativeStartTime: 0.1, relativeDuration: 0.1) {
capsuleDots.forEach({ dot in
dot.transform = .identity
dot.alpha = 1.0
})
}
// step 3: fade out dots and translate to the right
UIView.addKeyframe(withRelativeStartTime: 0.8, relativeDuration: 0.1) {
capsuleDots.forEach({ dot in
dot.alpha = 0.0
dot.transform = offstageRight
})
}
// step4: make capsure move to narrow width
UIView.addKeyframe(withRelativeStartTime: 0.9, relativeDuration: 0.1) {
capsule.bounds = capsuleFrameNarrow
}
})
}
// The following is just to add a UISlider into the view so that we can manually scrub the animation from 0 to 100%
// taken from: https://dzone.com/articles/ios-10-day-by-day-uiviewpropertyanimator
class ScrubReceiver: NSObject {
var onValueChange: ((Float) -> ())?
func performValueChangedHandler(slider: UISlider) {
onValueChange?(slider.value)
}
}
public class EventListener: NSObject {
public var eventFired: (() -> ())?
public func handleEvent() {
eventFired?()
}
}
let scrubber = UISlider(frame: CGRect(x: 0, y: 0, width: containerView.frame.width, height: 50))
containerView.addSubview(scrubber)
let eventListener = EventListener()
eventListener.eventFired = {
animator.fractionComplete = CGFloat(scrubber.value)
}
scrubber.addTarget(eventListener, action: #selector(EventListener.handleEvent), for: .valueChanged)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment