Last active
March 13, 2017 21:15
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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