So here is where I am at now. I still haven't been able to get it to work and I've tried a lot of variations. Here is my original code for a single animation.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
var images = [UIImage]()
var images2 = [UIImage]()
images += [#imageLiteral(resourceName: "circle1"), #imageLiteral(resourceName: "circle2"), #imageLiteral(resourceName: "circle3"), #imageLiteral(resourceName: "circle4")]
images2 += [#imageLiteral(resourceName: "circle4"), #imageLiteral(resourceName: "circle3"), #imageLiteral(resourceName: "circle2"), #imageLiteral(resourceName: "circle1")]
imageView.animationImages = images
imageView.animationDuration = 4.0
imageView.animationRepeatCount = 2
imageView.startAnimating()
}
}
I am able to animate the first images array with the properties I've set for duration and count. However, I just do not understand how I would write this to add a second set of images to animate immediately after. I know I need to use this somehow:
UIView
.animate(withDuration: 4.0,
animations: {
//animation 1
},
completion: { _ in
UIView.animate(withDuration: 6.0,
animations: {
//animation 2
})
})
Can someone show me how I would write this given my current images arrays using the same imageView object to display both animations? I want my first animation (images) to have a duration of 4 seconds and my second animation (images2) to have a duration of 6 second immediately following the first animation. I can't figure out what I need inside the animations parameter.
i think the error is that you mix here 2 things:
UIView.animate -> animate controls and properties
UIImageView.startAnimating -> start a loop of images in an UIImageView
but they don't do the same they are very independent. but UIView animation is normally for an other use case. only one thing is that they maybe have the same duration like your UIImageView animation, but you don't set the duration of your UIImageView. maybe when you set the animation duration of your image view to the duration of UIView animation then it is done on the same time range.
myImageView.animationDuration = 2;
and for the second loop
myImageView.animationDuration = 4;
Other Solutions
the thing is you need to know when an image loop ist completed. but there is no event for this (i did not found any)
there are some solutions on StackOverflow for this:
1 performSelector afterDelay
Set a timer to fire after the duration is done. for this you need also to add an animation duration to your image view:
myImageView.animationDuration = 0.7;
solution from here: how to do imageView.startAnimating() with completion in swift?:
When the button is pressed you can call a function with a delay
self.performSelector("afterAnimation", withObject: nil, afterDelay: imageView1.animationDuration)
Then stop the animation and add the last image of imageArray to the imageView in the afterAnimation function
func afterAnimation() {
imageView1.stopAnimating()
imageView1.image = imageArray.last
}
2 Timer
this is similar to performSelector afterDelay but with NSTimer.
you find a description here UIImageView startAnimating: How do you get it to stop on the last image in the series? :
1) Set the animation images property and start the animation (as in
your code in the question)
2) Schedule an NSTimer to go off in 'animationDuration' seconds time
3) When the timer goes off, [...]
add to point 3: then start the next animation
3 CATransaction
solution from here: Cocoa animationImages finish detection (you need to convert it to swift 3 syntax but it can be a starting point
Very old question, but I needed a fix now, this works for me:
[CATransaction begin];
[CATransaction setCompletionBlock:^{
DLog(#"Animation did finish.");
}];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.window.bounds];
imageView.animationDuration = 0.3 * 4.0;
imageView.animationImages = #[[UIImage AHZImageNamed:#"Default2"],
[UIImage AHZImageNamed:#"Default3"],
[UIImage AHZImageNamed:#"Default4"],
[UIImage AHZImageNamed:#"Default5"]];
imageView.animationRepeatCount = 1;
[self.window addSubview:imageView];
[imageView startAnimating];
[CATransaction commit];
4 Offtopic: Manual do the Image Animation
thats a little offtopic, because here they do the image animation manually. for your use case you just change the logic which image from index is visible. count forward until last image, then backwards until first image. and then stop the loop. not nice solution but in this solution is added a image transition animation:
Solution from here: Adding Image Transition Animation in Swift
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
let images = [
UIImage(named: "brooklyn-bridge.jpg")!,
UIImage(named: "grand-central-terminal.jpg")!,
UIImage(named: "new-york-city.jpg"),
UIImage(named: "one-world-trade-center.jpg")!,
UIImage(named: "rain.jpg")!,
UIImage(named: "wall-street.jpg")!]
var index = 0
let animationDuration: NSTimeInterval = 0.25
let switchingInterval: NSTimeInterval = 3
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = images[index++]
animateImageView()
}
func animateImageView() {
CATransaction.begin()
CATransaction.setAnimationDuration(animationDuration)
CATransaction.setCompletionBlock {
let delay = dispatch_time(DISPATCH_TIME_NOW, Int64(self.switchingInterval * NSTimeInterval(NSEC_PER_SEC)))
dispatch_after(delay, dispatch_get_main_queue()) {
self.animateImageView()
}
}
let transition = CATransition()
transition.type = kCATransitionFade
/*
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromRight
*/
imageView.layer.addAnimation(transition, forKey: kCATransition)
imageView.image = images[index]
CATransaction.commit()
index = index < images.count - 1 ? index + 1 : 0
}
}
Implement it as a custom image view would be better.
I know you said that this didn't work for you, but if you just want to execute animations right after another, I believe this really is the best option.
You should be able to do something like this:
let imageView = UIImageView()
UIView.animate(withDuration: 0.5, animations: {
//animation 1
}, completion: { (value: Bool) in
UIView.animate(withDuration: 1.0, animations: {
//animation 2
})
})
This does one animation directly after another, which a longer duration. Of course you still need to define what the animations are, but I hope this helps.
I'm not sure if this is the best way to do this, but I've found a solution to my problem. Please give feedback if there is a better way. I was able to accomplish multiple animations in a single UIImageView consecutively by using: self.perform(#selector(ViewController.afterAnimation), with: nil, afterDelay: 4.0)
This calls the afterAnimation function:
func afterAnimation() {
imageView.stopAnimating()
imageView.animationImages = images2
imageView.animationDuration = 6.0
imageView.animationRepeatCount = 1
imageView.startAnimating()
}
I needed animations to each last a specific amount of time and to be able to chain many of them together. It solves my problem.
Related
I've read many Stack Overflow questions in search of a solution for this, but I can't find one that addresses this particular issue in a way that works in iOS 13.
I have a label that I want to pulse repeatedly (like a slow, fading blink) once my view controller loads.
When it's time to transition away from the view, at the push of a button, I want to stop the pulsing at whatever alpha the pulsing label currently has, and then fade it out from there along with other UI elements.
In the past, I would have used a UIViewPropertyAnimator for this repeating animation, and then paused the animation once the button is tapped, but as of iOS 13 UIView.setAnimationRepeatCount(.greatestFiniteMagnitude) and UIView.setAnimationRepeatAutoreverses(true) are deprecated, which (I think) makes it impossible to build my pulse animation with a property animator.
Here is my example code:
import UIKit
class ViewController: UIViewController {
private lazy var pulsingLabel: UILabel = {
let label = UILabel()
label.text = "I am pulsing"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private lazy var stopButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Stop Pulsing",
for: .normal)
button.addTarget(self,
action: #selector(fadeEverythingOut),
for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(pulsingLabel)
view.addSubview(stopButton)
pulsingLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
pulsingLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
stopButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
stopButton.firstBaselineAnchor.constraint(equalToSystemSpacingBelow: pulsingLabel.lastBaselineAnchor,
multiplier: 4).isActive = true
startRepeatingAnimation()
}
private func startRepeatingAnimation() {
UIView.animate(withDuration: 1,
delay: 0,
options: [.repeat, .autoreverse, .curveEaseInOut],
animations: {
self.pulsingLabel.alpha = 0
})
}
#objc
private func fadeEverythingOut() {
pulsingLabel.layer.removeAllAnimations()
UIView.animate(withDuration: 2.0,
animations: {
self.pulsingLabel.alpha = 0
})
}
}
In this example, I'm calling pulsingLabel.layer.removeAllAnimations() to stop the animation, but this is not an acceptable solution because the label just immediately disappears when it's called.
I've also tried some weird stuff like sandwiching that line between UIView.setAnimationsEnabled(false) and UIView.setAnimationsEnabled(true), but that didn't work.
I also tried saving the alpha of pulsingLabel right before calling pulsingLabel.layer.removeAllAnimations() and then setting it again right after, but I always get a value of 0 for pulsingLabel.alpha.
Am I missing something here by abandoning UIViewPropertyAnimator, where I would still be able to get it to repeat, even with the deprecated functions on UIView? Or maybe I need to be calling .layer.removeAllAnimations() on a different layer or differently somehow?
Any ideas would be much appreciated, as I care quite a bit about getting these fine details right in my app!
I didn't see that you were looking for swift answer, but I only know ObjC right now. So here is the solution by timer (though in ObjC sorry):
In viewdidload:
self.angle = 0;
self.myTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(update) userInfo:nil repeats:YES];
angle is CGFloat to store current value to calculate the alpha by cosine function in update method:
-(void)update {
self.angle += M_PI/36.0;
if (self.angle > M_PI) self.angle = 0.0;
CGFloat val = (1 + cos(self.angle)) / 2.0;
dispatch_async(dispatch_get_main_queue(), ^{
self.myLabel.alpha = val;
});
}
You can adjust the value 36.0 to make the fade in/out slower or faster. val will give a swing value between 0 and 1 back and forth, as angle increases. Then using GCD we set the label alpha as needed in real time. When a button is pressed to move to another viewcontroller (as per your requirement), you only need to stop the timer by invalidating it, and the label will remain at whatever alpha is was set.
[self.myTimer invalidate];
self.myTimer = nil;
// CGFloat currentAlpha = self.myLabel.alpha;
From here, you can do other thing with label alpha.
I have the case, where the connect button is pressed, and continuously animated until the VPN has connected. Then I would like to stop the animation and load up a new set of images and animate that only once.
#IBOutlet weak var vpnButton: UIImageView!
var premiumImages: [UIImage] = []
var loadingImages: [UIImage] = []
#objc private func vpnStatusDidChange(_ notification: Notification) {
let nevpnconn = notification.object as! NEVPNConnection
let status = nevpnconn.status
switch status {
case NEVPNStatus.connecting:
self.animateImages(imageView: self.vpnButton, images: loadingImages, duration: 1.0, isInfinite: true)
self.vpnButton.image = UIImage(named: "Red-1")
}
The method that takes care of animation:
func animateImages(imageView: UIImageView, images: [UIImage], duration: Double, isInfinite: Bool=false) {
imageView.stopAnimating()
imageView.animationImages = images
imageView.animationDuration = duration
if !isInfinite {
imageView.animationRepeatCount = 1
} else {
imageView.animationRepeatCount = 0
}
imageView.startAnimating()
}
So whenever I call this, it would stop any existing animation in place and animate it with new images.
And once the VPN has connected:
case NEVPNStatus.connected:
self.vpnButton.highlightedImage = UIImage(named: "OrangePressed")
self.animateImages(imageView: self.vpnButton, images: premiumImages, duration: 0.25)
self.vpnButton.image = UIImage(named: "OrangePremium-3")
Only the loadingImages get properly animated. The second set premiumImages doesn't animate and only shows the last frame.
I suspect that stopAnimating() takes some time to accomplish, and ideally, I needed a completion handler here to know when to kick off the imageView.startAnimating().
Hi there,
I’ve been trying to solve a problem of how to create two progressViews in my viewController for the past week with little to no success. Please see the diagram I have attached as an idea as to the question I am asking.
I am creating a game with a timer which elapses with each question. As the time elapses I would like a UIProgressView to cascade down the entire screen transitioning from blue to white as it goes (Please see number 1 in the diagram, this indicates the white trackTintColor).
Number 2 in the diagram (the cyan part) represents the progressTintColor. The diagram should hopefully be clear in that I am hoping to customise the progressView so that it tracks downwards. Which is one of the main issues at the moment. (I can only seem to fins walkthroughs with small customisable Progressviews which move sideways not up and down)
The hardest part of what I am trying to achieve is (number 3 in the diagram), customisizing a UIImageView, so that it slowly drains downward with the inverse colours to the background (so the dog will be white with cyan flooding downwards to coincide with the progressView elapsing behind it).
These are the options I have tried to solve this issue, thus far, to no avail.
I have tried using a progressView for the backgroundColor, but I cannot find any examples anywhere of anyone else doing this (downwards)so I’m not sure if it’s even possible?
For the image I have tried drawing a CAShape layer but it appears the dog is too difficult a shape for a novice like myself to draw effectively. And upon realising that I would not be able to set a layer of a different colour behind the dog to move downwards as the screen will also be changing color I abandoned all hope of using this option.
I have tried a UIView transition for the dog image, however, the only option I could find that was anywhere close was the transitionCrossDissolve which did not give the downward effect I was hoping for, but instead just faded from a white dog to a cyan dog which was not appropriate. Should I somehow be using progressImage? If so, is there anywhere I can find help with the syntax for that? I can’t seem to find any anywhere.
I currently have 55 images in my assets folder, each with slightly more cyan in than the last, progressively moving downwards (as it animates through an array of the images). Although this works, it is not exactly seamless and does look a little like the user is waiting for an image to load on dial up.
If anyone has any ideas or could spare the time to walk me through how I would go about doing this I would very much appreciate it. I am very much still a beginner so the more detail the better! Oh yes to make matters more difficult, so far I have managed to do the app programatically, so an answers in this form would be great.
Thanks in advance!
I hope you have done number 1 and number 2, perfectly. I have tried for number 3.
I have tried with two UIView. Its working fine. I thought, it will give some idea to achieve yours.
I have two images.
With the help of TIMER , I tried sample for this ProgressView .
Intially, cyanDogView height should be Zero. Once Timer Starts, height should increased by 2px. Once cyanDogView's height should be greater than BlackDogView, then Timer Stops.
Coding
#IBOutlet weak var blackDogView: UIView!
#IBOutlet weak var blackDogImgVw: UIImageView!
#IBOutlet weak var cyanDogView: UIView!
#IBOutlet weak var cyanDogImgVw: UIImageView!
var getHeight : CGFloat = 0.0
var progressTime = Timer()
override func viewDidAppear(_ animated: Bool) {
cyanDogView.frame.size.height = 0
getHeight = blackDogView.frame.height
}
#IBAction func startAnimateButAcn(_ sender: UIButton) {
progressTime = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
}
#objc func update() {
cyanDogView.frame.size.height = cyanDogView.frame.size.height + 2
if cyanDogView.frame.size.height >= getHeight
{
progressTime.invalidate()
cyanDogView.frame.size.height = 0
}
}
Story Board
Output
I'm going to give you some Frankenstein answers here, Part Obj-C Part Swift. I hope it helps.
First, You could create a bezier path of the image mask you're using as a template:
- (UIImage *)cerateImageFromImage:(UIImage *)image
withMaskImage:(UIImage *)mask {
CGImageRef imageRef = image.CGImage;
CGImageRef maskRef = mask.CGImage;
CGImageRef imageMask = CGImageMaskCreate(CGImageGetWidth(maskRef),
CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef),
CGImageGetBytesPerRow(maskRef),
CGImageGetDataProvider(maskRef),
NULL,
YES);
CGImageRef maskedReference = CGImageCreateWithMask(imageRef, imageMask);
CGImageRelease(imageMask);
UIImage *maskedImage = [UIImage imageWithCGImage:maskedReference];
CGImageRelease(maskedReference);
return maskedImage;
}
UIImage *image = [UIImage imageNamed:#"Photo.png"];
UIImage *mask = [UIImage imageNamed:#"Mask.png"];
self.imageView.image = [self cerateImageFromImage:image
withMaskImage:mask];
Credit to Keenle
Next you can create a custom progress view based on a path :
func drawProgressLayer(){
let bezierPath = UIBezierPath(roundedRect: viewProg.bounds, cornerRadius: viewCornerRadius)
bezierPath.closePath()
borderLayer.path = bezierPath.CGPath
borderLayer.fillColor = UIColor.blackColor().CGColor
borderLayer.strokeEnd = 0
viewProg.layer.addSublayer(borderLayer)
}
//Make sure the value that you want in the function `rectProgress` that is going to define
//the width of your progress bar must be in the range of
// 0 <--> viewProg.bounds.width - 10 , reason why to keep the layer inside the view with some border left spare.
//if you are receiving your progress values in 0.00 -- 1.00 range , just multiply your progress values to viewProg.bounds.width - 10 and send them as *incremented:* parameter in this func
func rectProgress(incremented : CGFloat){
print(incremented)
if incremented <= viewProg.bounds.width - 10{
progressLayer.removeFromSuperlayer()
let bezierPathProg = UIBezierPath(roundedRect: CGRectMake(5, 5, incremented , viewProg.bounds.height - 10) , cornerRadius: viewCornerRadius)
bezierPathProg.closePath()
progressLayer.path = bezierPathProg.CGPath
progressLayer.fillColor = UIColor.whiteColor().CGColor
borderLayer.addSublayer(progressLayer)
}
}
Credit to Dravidian
Please click the blue links and explore their answers in full to get a grasp of what is possible.
Ok so using McDonal_11's answer I have managed to get the progressView working however, I am still experiencing some problems. I cannot add anything on top of the progressView, it just blanket covers everything else underneath, and before the dog begins its animation into a cyan dog there is a brief flash of the entire cyan dog image.
Code below
private let contentView = UIView(frame: .zero)
private let backgroundImageView = UIImageView(frame: .zero)
private let progressView = ProgressView(frame: .zero)
private let clearViewOverProgress = UIView(frame: .zero)
private let blackDogView = UIView(frame: .zero)
private let blackDogViewImage = UIImageView(frame: .zero)
private let cyanDogView = UIView(frame: .zero)
private let cyanDogViewImage = UIImageView()
var timer = Timer()
var startHeight : CGFloat = 0.0
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.progressView.setProgress(10.0, animated: true)
startHeight = cyanDogViewImage.frame.height
self.cyanDogViewImage.frame.size.height = 0
self.timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.updateImage), userInfo: nil, repeats: true)
}
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
func setupViews() {
self.view.addSubview(backgroundImageView)
self.backgroundImageView.addSubview(progressView)
self.progressView.addSubview(clearViewOverProgress)
self.clearViewOverProgress.addSubview(blackDogView)
self.blackDogView.addSubview(blackDogViewImage)
self.blackDogViewImage.addSubview(cyanDogView)
self.cyanDogView.addSubview(cyanDogViewImage)
// Setting up constraints of both labels (has been omitted for brevity)
self.blackDogViewImage.image = UIImage(named: “BlackDogImage”)
self.cyanDogViewImage.contentMode = UIViewContentMode.top
self.cyanDogViewImage.clipsToBounds = true
self.cyanDogViewImage.image = UIImage(named: “CyanDogImage”)
}
func updateImage() {
cyanDogViewImage.frame.size.height =
cyanDogViewImage.frame.size.height + 0.07
if cyanDogViewImage.frame.size.height >= blackDogViewImage.frame.size.height
{
timer.invalidate()
cyanDogViewImage.frame.size.height = blackDogViewImage.frame.size.height
}
}
func outOfTime() {
timer.invalidate()
}
First we generate a random number (for example from say 0 to 10):
If randomNumber = 0
Animate imageSet0 [here we create an ImageArray and an animate function – please see code below)
Else if randomNumber = 1
Animate imageSet1
Else if randomNumber = 2
Animate imageSet2
And so on…
Then we place a DispatchQueue timer that waits for the above animation to complete (time delay is equal to animationDuration), then we repeat the first step above and generate another random number and play another animation set:
DispatchQueue.main.asyncAfter(deadline: .now() + imageView.animationDuration) {
[Insert code that repeats the first step above and generates another random number to play another animation set]
}
In theory this random animation could play indefinitely until the user moves past this scene.
Here is my code thus far:
func createImageArray(total: Int, imagePrefix: String) -> [UIImage]{
var imageArray: [UIImage] = []
for imageCount in 0..<total {
let imageName = "\(imagePrefix)-\(imageCount).png"
let image = UIImage(named: imageName)!
imageArray.append(image)
}
return imageArray
}
func animate(imageView: UIImageView, images: [UIImage]){
imageView.animationImages = images
imageView.animationDuration = 1.0
imageView.animationRepeatCount = 1
imageView.startAnimating()
DispatchQueue.main.asyncAfter(deadline: .now() + imageView.animationDuration) {
[Create code that repeats the first step above and generates another random number to play another animation set]
}
}
You can use UIView.animate(withDuration: delay: options: animations:) api for that. Note delay parameter will let you start animation after certain delay.
I'm spending my turkey day trying to construct a flip animation class that I have been struggling with for weeks.
The goal is this:
Flip two images repeatedly, quickly at first, then slow down and stop, landing on one of the two images that was chosen before the animation began.
Right now both images are in a container view, in a storyboard. Ive tried using transitionFromView transitionFlipFromTop and I think that could work, but at the time I was unable to get it to repeat.
I am in the process of reading the View Programming Guide, but its tough to connect the dots between it, and swift. Being new to programming in general does not help.
Here is where I'm at: I'm now using a CATransform to scale an image from zero height, to full height. Im thinking that if I can somehow chain two animations, the first one showing the first image scaling up, then back down to zero, then animate the second image doing the same thing, that should give me the first part. Then if I could somehow get those two animations to repeat, quickly at first, then slow down and stop.
It seems I need to know how to nest multiple animations, and then be able to apply an animation curve to the nested animation.
I planned on solving the part about landing on a particular image by having two of these nested animations, one of them would have an odd number of flips, the other an even number of flips. Depending on the desired final image, the appropriate animation gets called.
Right now, my current code is able to repeatedly scale an image from zero to full, a set number of times:
import UIKit
import QuartzCore
let FlipAnimatorStartTransform:CATransform3D = {
let rotationDegrees: CGFloat = -15.0
let rotationRadians: CGFloat = rotationDegrees * (CGFloat(M_PI)/180.0)
let offset = CGPointMake(-20, -20)
var startTransform = CATransform3DIdentity
startTransform = CATransform3DScale(CATransform3DMakeRotation(0, 0, 0, 0),
1, 0, 1);
return startTransform
}()
class FlipAnimator {
class func animate(view: UIView) {
let viewOne = view
let viewTwo = view
viewOne.layer.transform = FlipAnimatorStartTransform
viewTwo.layer.transform = FlipAnimatorStartTransform
UIView.animateWithDuration(0.5, delay: 0, options: .Repeat, {
UIView.setAnimationRepeatCount(7)
viewOne.layer.transform = CATransform3DIdentity
},nil)
}
}
Im going to keep chipping away at it. Any help, or ideas, or hints about a better way to go about it would be amazing.
Thanks.
I'm using this function to rotate image horizontally and to change the image during the transition.
private func flipImageView(imageView: UIImageView, toImage: UIImage, duration: NSTimeInterval, delay: NSTimeInterval = 0)
{
let t = duration / 2
UIView.animateWithDuration(t, delay: delay, options: .CurveEaseIn, animations: { () -> Void in
// Rotate view by 90 degrees
let p = CATransform3DMakeRotation(CGFloat(GLKMathDegreesToRadians(90)), 0.0, 1.0, 0.0)
imageView.layer.transform = p
}, completion: { (Bool) -> Void in
// New image
imageView.image = toImage
// Rotate view to initial position
// We have to start from 270 degrees otherwise the image will be flipped (mirrored) around Y axis
let p = CATransform3DMakeRotation(CGFloat(GLKMathDegreesToRadians(270)), 0.0, 1.0, 0.0)
imageView.layer.transform = p
UIView.animateWithDuration(t, delay: 0, options: .CurveEaseOut, animations: { () -> Void in
// Back to initial position
let p = CATransform3DMakeRotation(CGFloat(GLKMathDegreesToRadians(0)), 0.0, 1.0, 0.0)
imageView.layer.transform = p
}, completion: { (Bool) -> Void in
})
})
}
Don't forget to import GLKit.
This flip animation swift code appears little better:
let transition = CATransition()
transition.startProgress = 0;
transition.endProgress = 1.0;
transition.type = "flip";
transition.subtype = "fromRight";
transition.duration = 0.9;
transition.repeatCount = 2;
self.cardView.layer.addAnimation(transition, forKey: " ")
Other option is
#IBOutlet weak var cardView: UIView!
var back: UIImageView!
var front: UIImageView!
self.front = UIImageView(image: UIImage(named: "heads.png"))
self.back = UIImageView(image: UIImage(named: "tails.png"))
self.cardView.addSubview(self.back)
UIView.transitionFromView(self.back, toView: self.front, duration: 1, options: UIViewAnimationOptions.TransitionFlipFromRight , completion: nil)
Please check link
It seems I need to know how to nest multiple animations, and then be able to apply an animation curve to the nested animation.
I don't think so. I don't think you want/need to nest anything. You are not repeating an animation in this story; you are doing different animations each time (because the durations are to differ). This is a sequence of animations. So I think what you need to know is how to do either a keyframe animation or a grouped animation. That way you can predefine a series of animations, each one lasting a certain predefined duration, each one starting after the preceding durations are over.
And for that, I think you'll be happiest at the Core Animation level. (You can't make a grouped animation at the UIView animation level anyway.)