2

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.

Zaporozhchenko Oleksandr
  • 4,660
  • 3
  • 26
  • 48
schulzey
  • 95
  • 1
  • 2
  • 9
  • Most people are new. We know that. Doesn't matter. Just ask you question, and please format code properly so it all fits in code block. – clearlight Jan 23 '17 at 01:01
  • Thank you for the advice. I will follow this in this future. – schulzey Jan 23 '17 at 01:40
  • please use for variables like `ImageView` a first lowercase letter to avoid confusion between a var (always first lowercased) and a class name (always first uppercased) – muescha Jan 23 '17 at 16:40

3 Answers3

3

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.

Benjamin Lowry
  • 3,730
  • 1
  • 23
  • 27
  • It wasn't working when I tried to use the same imageView for both animations. I'll try again and post my progress. Thank you very much for your response. – schulzey Jan 23 '17 at 01:42
  • I still can't figure it out so I edited my post. What would go inside of the animations parameter? – schulzey Jan 23 '17 at 23:42
  • @schulzey Can you add the actual code that you've used in my code blocks so I have a better idea of how to help you make the animations consecutive? – Benjamin Lowry Jan 24 '17 at 00:20
  • `var imageView = UIImageView() UIView.animate(withDuration: 4.0, animations: { imageView.animationImages = images }, completion: { (value: Bool) in UIView.animate(withDuration: 6.0, animations: { imageView.animationImages = images2 }) })` – schulzey Jan 24 '17 at 03:17
  • @schulzey Ah I see why that isn't working. Doing this type of animation actually isn't for setting attributes, but rather for changing a frame. Sorry for the confusion but my method is for something more like `imageView.frame.origin.x += 50` – Benjamin Lowry Jan 24 '17 at 03:22
  • Thank you for the clarification. – schulzey Jan 24 '17 at 05:12
  • @BenjaminLowry im having the same issues here with multiple consecutive animations not working. Even when doing something like `imageView.frame.origin.x += 50` – Michael Ramos Aug 22 '17 at 13:20
3

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.

Community
  • 1
  • 1
muescha
  • 1,544
  • 2
  • 12
  • 22
  • If you look at the other answer to this post at the bottom – schulzey Jan 23 '17 at 19:57
  • If you look at the other answer to this post at the bottom, I just need the syntax that would go inside of each animation. What I have does not work. – schulzey Jan 23 '17 at 20:03
  • ok - i see you updated your question. but still your `animationDuration=4.0` not match the duration of `UIView.animate(withDuration: 0.5` there should be also a `4.0` – muescha Jan 24 '17 at 01:31
  • did you try die other solutions i provided? – muescha Jan 24 '17 at 01:31
  • A variation of your first recommendation worked. I'm assuming that's just older swift syntax. It feels a little patched together this way, but having a delay for consecutive animations does work. thank you! – schulzey Jan 24 '17 at 05:10
  • yes the exact syntax is up to your needs but i give you the final hint how you can solve it. it would be nice when you accept my answer (klick at the gray checkmark on the left side) – muescha Jan 24 '17 at 07:39
1

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.

schulzey
  • 95
  • 1
  • 2
  • 9