Change animation speed on slider - ios

If you scroll to the bottom you'll see a slider for changing the animation speed. What I'd like to do is create an animation speed on the slider based around the replicatorLayer animation2() part. Is this possible?
var player:AVAudioPlayer = AVAudioPlayer()
var meditationState: MeditationState?
var replicatorLayer = CAReplicatorLayer()
var dot = CALayer()
func updateTimer(){
seconds += 1
timerclock.text = "\(seconds)"
}
// Animation starts running
func animation2() {
// A layer that creates a specified number of copies of its sublayers (the source layer), each copy potentially having geometric, temporal, and color transformations applied to it.
replicatorLayer = CAReplicatorLayer()
// The layer’s bounds rectangle. Animatable.
replicatorLayer.bounds = CGRect(x: 0.0, y: 0.0, width: 300.0, height: 300.0)
// The radius to use when drawing rounded corners for the layer’s background. Animatable.
replicatorLayer.cornerRadius = 10.0
// The background color of the receiver. Animatable.
replicatorLayer.backgroundColor = UIColor(white: 0.0, alpha: 0.0).cgColor
// The layer’s position in its superlayer’s coordinate space. Animatable.
replicatorLayer.position = view.center
// calling this method creates an array for that property and adds the specified layer to it.
view.layer.addSublayer(replicatorLayer)
// connectng the animation to the content
// An object that manages image-based content and allows you to perform animations on that content
dot = CALayer()
// The layer’s bounds rectangle. Animatable.
dot.bounds = CGRect(x: 0.0, y: 0.0, width: 12.0, height: 12.0)
//The layer’s position in its superlayer’s coordinate space. Animatable.
dot.position = CGPoint(x: 150.0, y: 40.0)
//The background color of the receiver. Animatable.
dot.backgroundColor = UIColor(white: 0.2, alpha: 1.0).cgColor
// The color of the layer’s border. Animatable.
dot.borderColor = UIColor(white: 1.0, alpha: 1.0).cgColor
// The width of the layer’s border. Animatable.
dot.borderWidth = 1.0
//The radius to use when drawing rounded corners for the layer’s background. Animatable.
dot.cornerRadius = 5.0
//Appends the layer to the layer’s list of sublayers.
replicatorLayer.addSublayer(dot)
// number of copies of layer is instanceCount
let nrDots: Int = 1000
//The number of copies to create, including the source layers.
replicatorLayer.instanceCount = nrDots
// The basic type for floating-point scalar values in Core Graphics and related frameworks.
let angle = CGFloat(2*M_PI) / CGFloat(nrDots)
// The transform matrix applied to the previous instance to produce the current instance. Animatable.
replicatorLayer.instanceTransform = CATransform3DMakeRotation(angle, 0.0, 0.0, 1.0)
// Type used to represent elapsed time in seconds.
let duration: CFTimeInterval = 10.0
// animation capabilities for a layer property.
// An object that provides basic, single-keyframe animation capabilities for a layer property.
let shrink = CABasicAnimation(keyPath: "transform.scale")
// Defines the value the receiver uses to start interpolation.
shrink.fromValue = 1.0
// Defines the value the receiver uses to end interpolation.
shrink.toValue = 0.1
// Specifies the basic duration of the animation, in seconds.
shrink.duration = duration
// Determines the number of times the animation will repeat.
shrink.repeatCount = Float.infinity
// Add the specified animation object to the layer’s render tree.
dot.add(shrink, forKey: "shrink")
// Specifies the delay, in seconds, between replicated copies. Animatable.
replicatorLayer.instanceDelay = duration/Double(nrDots)
// The transform applied to the layer’s contents. Animatable.
dot.transform = CATransform3DMakeScale(0.01, 0.01, 0.01)
}
// connecting the breathe in label
#IBOutlet weak var label: UILabel!
// instant delay
#IBOutlet weak var instantDelay: UIButton!
#IBAction func delayBtn(_ sender: Any) {
dot.removeAnimation(forKey: "shrink")
timer1.invalidate()
seconds = 0
timer2.invalidate()
timerclock.text = "\(seconds)"
time = 0
timerLabel.text = "Breathe in"
timerisOn = false
pauseBtn.isHidden = true
playBtn.isHidden = false
label.isHidden = true
replicatorLayer.isHidden = true
instantDelay.isHidden = true
instantDelay1.isHidden = false
slider.isHidden = false
}
// Delay 1
#IBOutlet weak var instantDelay1: UIButton!
#IBAction func delayBtn1(_ sender: Any) {
instantDelay1.isHidden = true
instantDelay.isHidden = false
label.isHidden = false
slider.isHidden = true
}
//Slider for changing animation speed
#IBOutlet weak var slider: UISlider!
#IBAction func slider(_ sender: Any) {
}

CALayer conforms to the CAMediaTiming protocol, which means it has a speed property. When you change the speed property of a layer it alters the "frame of reference" of all child layers. (Speed == 1.0 is normal speed, speed 2.0 is double-speed, and speed 0.5 is half-speed.)
You can change the speed property of the parent layer that contains your replicator layer and it should alter the speed of your animation. Try making a valueChanged IBAction attached to your slider that changes the speed property of your animation's super layer to values ranging from 0.5 to 2.0.
CAAnimation objects also conform to the CAMediaTiming protocol, so you can change the speed on individual animations as well.
EDIT:
It's not complicated. You could make your slider IBAction method something like this:
#IBAction func slider(_ sender: UISlider) {
view.layer.speed = sender.value
}

Related

Swift image appear animation from bottom of its frame to top (wipe animation)

I just want to get some ideas on how to approach the situation I have in hand.
I have created some images which I want to animate, but the animation I want is not default given, so its giving me some hard time.
The animation I want is like this: https://i.stack.imgur.com/byGMC.gif (not from bottom of the screen, from the bottom of images' own frame)
When a button is pressed I want the button/image start appear from bottom of its frame to the top, like the wipe animation in powerpoint :)
So naturaly it will default as hidden and when a button is pressed it will animate in.
I did try a few methods but non of them is actually doing the job I want.
Like this one:
extension UIView{
func animShow(){
UIView.animate(withDuration: 2, delay: 5, options: [.transitionFlipFromBottom],
animations: {
self.center.y -= self.bounds.height
self.layoutIfNeeded()
}, completion: nil)
self.isHidden = false
}
func animHide(){
UIView.animate(withDuration: 1, delay: 0, options: [.curveLinear],
animations: {
self.center.y += self.bounds.height
self.layoutIfNeeded()
}, completion: {(_ completed: Bool) -> Void in
self.isHidden = true
})
}
}
so it slides in the image but this is not what I want, you may try the code, just add this and write image.animShow() in viewDidLoad, button is the button which I want to animate.
I appreciate every bit of help, and I am a newbie in swift programming
Thank you.
There are various ways to do a "soft wipe" animation... here is one.
We can add a gradient layer mask and then animate the gradient.
When using a layer mask, clear (alpha 0) areas hide what's under the mask, and opaque (alpha 1) areas show what's under the mask. This includes parts of the mask that are translucent - alpha 0.5 for example - so the content becomes "translucent".
To get a "soft wipe" we want the gradient to use only a portion of the frame, so if we set the starting Y point to 0.5 (halfway down), for example, we can set the ending Y point to 0.6 ... this would give us a horizontal "gradient band".
So, a yellow-to-red gradient at 0.5 to 0.6 would look like this:
If we set the starting Y to 1.0 and the ending Y to 1.1, the gradient band will start "off the bottom of the view" ... and we can animate it up until it's "off the top of the view" (note that converted to gif loses some of the smooth gradient property):
Now, if we instead use clear-to-red and set it as a layer mask, using the same animation it will "soft wipe" the view, it will look something like this:
Can't get the animated gif small enough to post here, so here's a link to the animation: https://i.imgur.com/jo2DH3Z.mp4
Here's some sample code for you to play with. Lots of comments in there:
class AnimatedGradientImageView: UIImageView {
let maskLayer = CAGradientLayer()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
// vertical gradient
// start at bottom
maskLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
// to bottom + 1/10th
maskLayer.endPoint = CGPoint(x: 0.5, y: 1.1)
// use "if true" to see the layer itself
// use "if false" to see the image reveal
if false {
// yellow to red
maskLayer.colors = [UIColor.yellow.cgColor, UIColor.red.cgColor]
// add it as a sublayer
layer.addSublayer(maskLayer)
} else {
// clear to red
maskLayer.colors = [UIColor.clear.cgColor, UIColor.red.cgColor]
// set the mask
layer.mask = maskLayer
}
}
override func layoutSubviews() {
super.layoutSubviews()
// set mask layer frame
maskLayer.frame = bounds
}
func reveal() -> Void {
let anim1: CABasicAnimation = CABasicAnimation(keyPath: "startPoint.y")
// anim1 animates the gradient start point Y
// to -0.1 (1/10th above the top of the view)
anim1.toValue = -0.1
anim1.duration = 1.0
anim1.isRemovedOnCompletion = false
anim1.fillMode = .forwards
let anim2: CABasicAnimation = CABasicAnimation(keyPath: "endPoint.y")
// anim2 animates the gradient end point Y
// to 0.0 (the top of the view)
anim2.toValue = 0.0
anim2.duration = 1.0
anim2.isRemovedOnCompletion = false
anim2.fillMode = .forwards
maskLayer.add(anim1, forKey: nil)
maskLayer.add(anim2, forKey: nil)
}
}
class AnimatedGradientViewController: UIViewController {
let testImageView = AnimatedGradientImageView(frame: .zero)
override func viewDidLoad() {
super.viewDidLoad()
// replace with your image name
guard let img = UIImage(named: "sampleImage") else {
fatalError("Could not load image!!!")
}
// set the image
testImageView.image = img
testImageView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(testImageView)
// respect safe area
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// size: 240 x 240
testImageView.widthAnchor.constraint(equalToConstant: 240.0),
testImageView.heightAnchor.constraint(equalToConstant: 240.0),
// centered
testImageView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
testImageView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
])
// tap anywhere in the view
let t = UITapGestureRecognizer(target: self, action: #selector(gotTap(_:)))
view.addGestureRecognizer(t)
}
#objc func gotTap(_ g: UITapGestureRecognizer) -> Void {
testImageView.reveal()
}
}
First, you will have to give the height constraint of the image from the storyboard and set the height to 0
and take the image height constraint into your file like below
#IBOutlet weak var imageHeight: NSLayoutConstraint!
Here is the animation code.
UIView.animate(withDuration: 2, delay: 2, options: [.transitionFlipFromBottom],
animations: {
self.image.frame = CGRect(x: self.image.frame.origin.x, y: self.image.frame.origin.y - 100, width: self.image.frame.size.width, height: 100)
self.imageHeight.constant = 100
self.image.layoutIfNeeded()
}, completion: nil)
Click here to see animation

Synchronously animate CALayer property and UIView with UIViewPropertyAnimator

I'm using a UIViewPropertyAnimator to animate the position of a view. But, I also want to animate CALayer properties like borderColor along with it. Currently, it doesn't animate and instantly changes at the start, like this:
Here's my code:
class ViewController: UIViewController {
var animator: UIViewPropertyAnimator?
let squareView = UIView(frame: CGRect(x: 0, y: 40, width: 80, height: 80))
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(squareView)
squareView.backgroundColor = UIColor.blue
squareView.layer.borderColor = UIColor.green.cgColor
squareView.layer.borderWidth = 6
animator = UIViewPropertyAnimator(duration: 2, curve: .easeOut, animations: {
self.squareView.frame.origin.x = 100
self.squareView.layer.borderColor = UIColor.red.cgColor
})
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.animator?.startAnimation()
}
}
}
I looked at this question, How to synchronously animate a UIView and a CALayer, and the answer suggested using "an explicit animation, like a basic animation." It said,
If the timing function and the duration of both animations are the same then they should stay aligned.
However, if I use CABasicAnimation, I lose all the benefits of UIViewPropertyAnimator, like timing and stopping in the middle. I will also need to keep track of both. Is there any way to animate CALayer properties with UIViewPropertyAnimator?
CABasicAnimation has timing as well as keyframe animation to stop in the middle. But, to replicate your animation above:
squareView.layer.transform = CATransform3DMakeTranslation(100, 0, 0)
let fromValue = squareView.transform
let toValue = 100
let translateAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.transform))
translateAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
translateAnimation.fromValue = fromValue
translateAnimation.toValue = toValue
translateAnimation.valueFunction = CAValueFunction(name: .translateX)
let fromColor = squareView.layer.borderColor
let toColor = UIColor.red.cgColor
let borderColorAnimation = CABasicAnimation(keyPath: "borderColor")
borderColorAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
borderColorAnimation.fromValue = fromColor
borderColorAnimation.toValue = toColor
let groupAnimation = CAAnimationGroup()
groupAnimation.animations = [translateAnimation, borderColorAnimation]
groupAnimation.duration = 5
squareView.layer.add(groupAnimation, forKey: nil)

Animation of a circle in iOS

I'm learning how to use SpriteKit and would like to have a circle that:
Grows and shrinks smoothly
Pulses with a colour
Is displayed with crisp edges
So far, I've come up with the following code:
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
addCircle()
}
func addCircle(){
let circle = SKShapeNode(circleOfRadius: 50 ) // Size of Circle
circle.position = CGPointMake(frame.midX, frame.midY) //Middle of Screen
circle.glowWidth = 0.0 // No border
circle.fillColor = SKColor.yellowColor() // Start as yellow
let actualDuration = 1 // Animate for 1s
// Basic actions for grow, shrink, colour up, colour down
let actionGrow = SKAction.scaleTo(CGFloat(2), duration: NSTimeInterval(actualDuration))
actionGrow.timingMode = SKActionTimingMode.EaseInEaseOut
let actionShrink = SKAction.scaleTo(CGFloat(0.5), duration: NSTimeInterval(actualDuration))
actionShrink.timingMode = SKActionTimingMode.EaseInEaseOut
let actionColorUp = SKAction.colorizeWithColor(UIColor.redColor(), colorBlendFactor: 1.0, duration: NSTimeInterval(actualDuration))
let actionColorDown = SKAction.colorizeWithColor(UIColor.redColor(), colorBlendFactor: 0.0, duration: NSTimeInterval(actualDuration))
// Combine the actions
let actionGrowWithColor = SKAction.group([actionGrow,actionColorUp])
let actionShrinkWithColor = SKAction.group([actionShrink,actionColorDown])
// Run and repeat
circle.runAction(SKAction.repeatActionForever(SKAction.sequence([actionGrowWithColor,actionShrinkWithColor])))
// Add the circle
self.addChild(circle)
}
}
The first of my three criteria are met, but the other two are not.
As the SKShapeNode is not a vector, as it grows the edges are not crisp. Is there a better way to draw a circle, or should I just start with a circle that is sufficiently large?
Is there a reason why the colorizeWithColor section doesn't appear to have any effect?
Many thanks in advance!

What is the right way of creating circle animation?

I just saw this image and it's interesting to me, how to create such type of animation in Swift:
So, I have many gray teeth in circle and when I set the angle, for example 45degree it will fill these gray teeth into blue within 0..45 degree.
You can just explain me the right way of doing it or you can show different snippets(it would be great). And later I will search or read about it.
Thanks in advance!
If you only need the individual 'teeth' to change color, instead of using the teeth as masks for a solid fill, you can use Core Graphics instead of Core Animation (although Core Animation is generally preferred). So in order to do this, we should be doing the following:
Subclass UIView to insert our drawing code
Create an array of path objects, wrapped in UIBezierPath
Setup a timer to update a progress value and setNeedsDisplay
In drawRect:, draw the paths and assign a fill to each depending on the progress
First of all, lets define the variables we're going to be working with in this UIView subclass.
class TeethLoaderView : UIView {
let numberOfTeeth = UInt(60) // Number of teeth to render
let teethSize = CGSize(width:8, height:45) // The size of each individual tooth
let animationDuration = NSTimeInterval(5.0) // The duration of the animation
let highlightColor = UIColor(red: 29.0/255.0, green: 175.0/255.0, blue: 255.0/255.0, alpha: 1) // The color of a tooth when it's 'highlighted'
let inactiveColor = UIColor(red: 233.0/255.0, green: 235.0/255.0, blue: 236.0/255.0, alpha: 1) // The color of a tooth when it isn't 'hightlighted'
var progress = NSTimeInterval(0.0) // The progress of the loader
var paths = [UIBezierPath]() // The array containing the UIBezier paths
var displayLink = CADisplayLink() // The display link to update the progress
var teethHighlighted = UInt(0) // Number of teeth highlighted
...
Now let's add a function to create our paths.
func getPaths(size:CGSize, teethCount:UInt, teethSize:CGSize, radius:CGFloat) -> [UIBezierPath] {
let halfHeight = size.height*0.5;
let halfWidth = size.width*0.5;
let deltaAngle = CGFloat(2*M_PI)/CGFloat(teethCount); // The change in angle between paths
// Create the template path of a single shape.
let p = CGPathCreateWithRect(CGRectMake(-teethSize.width*0.5, radius, teethSize.width, teethSize.height), nil);
var pathArray = [UIBezierPath]()
for i in 0..<teethCount { // Copy, translate and rotate shapes around
let translate = CGAffineTransformMakeTranslation(halfWidth, halfHeight);
var rotate = CGAffineTransformRotate(translate, deltaAngle*CGFloat(i))
let pathCopy = CGPathCreateCopyByTransformingPath(p, &rotate)!
pathArray.append(UIBezierPath(CGPath: pathCopy)) // Populate the array
}
return pathArray
}
This is fairly simple. We just create a path for a single 'tooth' and then copy this path for how many teeth we need, translating and rotating the path for each one.
Next we want to setup our view. I'm going to a CADisplayLink for the timer so that the animation performs at the same speed on all devices.
override init(frame: CGRect) {
super.init(frame: frame)
commonSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonSetup()
}
private func commonSetup() {
self.backgroundColor = UIColor.whiteColor()
paths = getPaths(frame.size, teethCount: numberOfTeeth, teethSize: teethSize, radius: ((frame.width*0.5)-teethSize.height))
displayLink = CADisplayLink(target: self, selector: #selector(displayLinkDidFire));
displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}
Here we just set the background color, as well as setup our timer and initialise the paths we're going to be using. Next we want to setup a function to change the progress of the view when the CADisplayLink fires.
func displayLinkDidFire() {
progress += displayLink.duration/animationDuration
if (progress > 1) {
progress -= 1
}
let t = teethHighlighted
teethHighlighted = UInt(round(progress*NSTimeInterval(numberOfTeeth))) // Calculate the number of teeth to highlight
if (t != teethHighlighted) { // Only call setNeedsDisplay if the teethHighlighted changed
setNeedsDisplay()
}
}
Nothing complicated here, we just update the progress and teethHighlighted and call setNeedsDisplay() to redraw the view, if teethHighlighted changed.
Finally, we want to draw the view.
override func drawRect(rect: CGRect) {
let ctx = UIGraphicsGetCurrentContext()
CGContextScaleCTM(ctx, -1, -1) // Flip the context to the correct orientation
CGContextTranslateCTM(ctx, -rect.size.width, -rect.size.height)
for (index, path) in paths.enumerate() { // Draw each 'tooth'
CGContextAddPath(ctx, path.CGPath);
let fillColor = (UInt(index) <= teethHighlighted) ? highlightColor:inactiveColor;
CGContextSetFillColorWithColor(ctx, fillColor.CGColor)
CGContextFillPath(ctx)
}
}
If you wanted to go down the Core Animation path, I adapted this code into a Core Animation layer
Final Result
Full project: https://github.com/hamishknight/Circle-Loader
Well, in the spirit of "go big or go home" (and because I'm actually having some fun doing this), I created a Core Animation version of my Core Graphics answer. It's quite a bit less code and animates smoother, so I'd actually prefer to use this.
First off, let's subclass a UIView again (this isn't strictly necessary, but it's nice to contain everything in a single view) and define our variables:
class TeethLoaderViewCA : UIView {
let numberOfTeeth = UInt(60) // Number of teetch to render
let teethSize = CGSize(width:8, height:45) // The size of each individual tooth
let animationDuration = NSTimeInterval(5.0) // The duration of the animation
let highlightColor = UIColor(red: 29.0/255.0, green: 175.0/255.0, blue: 255.0/255.0, alpha: 1) // The color of a tooth when it's 'highlighted'
let inactiveColor = UIColor(red: 233.0/255.0, green: 235.0/255.0, blue: 236.0/255.0, alpha: 1) // The color of a tooth when it isn't 'hightlighted'
let shapeLayer = CAShapeLayer() // The teeth shape layer
let drawLayer = CAShapeLayer() // The arc fill layer
let anim = CABasicAnimation(keyPath: "strokeEnd") // The stroke animation
...
This is mostly the same as the Core Graphics version, but with a couple of Core Animation objects and without the timing logic. Next, we can pretty much copy the getPaths function we created in the other version, except with a few tweaks.
func getPathMask(size:CGSize, teethCount:UInt, teethSize:CGSize, radius:CGFloat) -> CGPathRef? {
let halfHeight = size.height*0.5
let halfWidth = size.width*0.5
let deltaAngle = CGFloat(2*M_PI)/CGFloat(teethCount); // The change in angle between paths
// Create the template path of a single shape.
let p = CGPathCreateWithRect(CGRectMake(-teethSize.width*0.5, radius, teethSize.width, teethSize.height), nil)
let returnPath = CGPathCreateMutable()
for i in 0..<teethCount { // Copy, translate and rotate shapes around
let translate = CGAffineTransformMakeTranslation(halfWidth, halfHeight)
var rotate = CGAffineTransformRotate(translate, deltaAngle*CGFloat(i))
CGPathAddPath(returnPath, &rotate, p)
}
return CGPathCreateCopy(returnPath)
}
This time, all the paths are grouped into one big path and the function returns that path.
Finally, we just have to create our layer objects & setup the animation.
private func commonSetup() {
// set your background color
self.backgroundColor = UIColor.whiteColor()
// Get the group of paths we created.
shapeLayer.path = getPathMask(frame.size, teethCount: numberOfTeeth, teethSize: teethSize, radius: ((frame.width*0.5)-teethSize.height))
let halfWidth = frame.size.width*0.5
let halfHeight = frame.size.height*0.5
let halfDeltaAngle = CGFloat(M_PI/Double(numberOfTeeth))
// Creates an arc path, with a given offset to allow it to be presented nicely
drawLayer.path = UIBezierPath(arcCenter: CGPointMake(halfWidth, halfHeight), radius: halfWidth, startAngle: CGFloat(-M_PI_2)-halfDeltaAngle, endAngle: CGFloat(M_PI*1.5)+halfDeltaAngle, clockwise: true).CGPath
drawLayer.frame = frame
drawLayer.fillColor = inactiveColor.CGColor
drawLayer.strokeColor = highlightColor.CGColor
drawLayer.strokeEnd = 0
drawLayer.lineWidth = halfWidth
drawLayer.mask = shapeLayer
layer.addSublayer(drawLayer)
// Optional, but looks nice
anim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
}
All we're doing here is assigning the group of paths to a CAShapeLayer, which we will use as a mask over the drawLayer, which we will be animating around the view (using a stroke on an arch path).
Final Result
Full project: https://github.com/hamishknight/Circle-Loader

UIImageView animation in Swift with time delay

I'm stuck with this issue where I want a UIImage to glow within two seconds and then to go back to it's normal state.
Given this issue here's what I have at the moment:
I have the image views referenced, from 0 to 9.
#IBOutlet weak var imageOne: UIImageView!
#IBOutlet weak var imageTwo: UIImageView!
etc.
Then I added them to SubViews in the viewDiDLoad() function:
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(imageOne)
self.view.addSubview(imageTwo)
etc.
}
Here is my implementation of the colorisation function:
func colorize(imageView: UIImageView, color: CGColorRef) {
imageView.layer.shadowColor = color
imageView.layer.shadowRadius = 7.0
imageView.layer.shadowOpacity = 0.9
imageView.layer.shadowOffset = CGSizeZero
imageView.layer.masksToBounds = false
}
Now, I'm trying to animate two image views which are called through this. a and b are just randoms acquired from the previous view. In this example, they will be 1 and 3.:
UIView.animateWithDuration(2.0, delay: 0, options: nil, animations: { () -> Void in
self.colorize(labelArray[a.toInt()!], color:self.green)
}, completion: nil)
UIView.animateWithDuration(2.0, delay: 2.0, options: nil, animations: { () -> Void in
self.colorize(labelArray[b.toInt()!], color:self.cyan)
}, completion: nil)
Now, this is what the view looks like beforehand -
And this is what it's like after, but both animations occur at the same time. There is no transition. It just automatically applies the glow -
Thanks for your help!
Since you're trying to animation your UIImageView layers, try using Core Animation instead of UIView animation blocks since Core Animation must be used to animate the shadow layer of a view. If you simply want to fade the shadow in, try this to animate the shadow opacity:
override func performGlowAnimations {
self.colorize(labelArray[a.toInt()!], color:self.green)
// Delay the second call by 2 seconds
let delay = 2.0 * Double(NSEC_PER_SEC)
var time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), {
self.colorize(labelArray[b.toInt()!], color:self.cyan)
})
}
func colorize(imageView: UIImageView, color: CGColorRef) {
// Set the image's shadowColor, radius, offset, and
// set masks to bounds to false
imageView.layer.shadowColor = color
imageView.layer.shadowRadius = 7.0
imageView.layer.shadowOffset = CGSizeZero
imageView.layer.masksToBounds = false
// Animate the shadow opacity to "fade it in"
let shadowAnim = CABasicAnimation()
shadowAnim.keyPath = "shadowOpacity"
shadowAnim.fromValue = NSNumber(float: 0.0)
shadowAnim.toValue = NSNumber(float: 0.9)
shadowAnim.duration = 2.0
imageView.layer.addAnimation(shadowAnim, forKey: "shadowOpacity")
imageView.layer.shadowOpacity = 0.9
}

Resources