1

I am totally new to iOS and I am working on an application that has many frame animations. Everything is going well until I try to do my final animation in a method that I am posting below. The method is a delegate assigned to the Built in Text to Speech synthesizer

func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
        if spoken == 0{
            spoken += 1
            print("speaking finished")
            self.ImageView.stopAnimating()
            self.ImageView.image = self.circleImages.last
            self.ImageView.animationImages = self.circleImages
            self.ImageView.animationDuration = 1.5
            self.ImageView.animationRepeatCount = 0
            self.ImageView.startAnimating()
            do{
                try self.recordAndRecognizeSpeech()

            }catch let error{
                print(error)
            }          
        }else if spoken == 1{
                //animation 1
                spoken += 1
                            //animation 1
                self.ImageView.image = self.comingOutImages.first
                self.ImageView.animationImages = self.comingOutImages
                self.ImageView.animationDuration = 6.0
                self.ImageView.animationRepeatCount = 1
                self.ImageView.startAnimating()
                print(String(self.comingOutImages.count) + " #of images")


                print("should have animated go in" + String(spoken))     
        }else{
            print("done")
        }

    }

The firs block of the method where spoken == 0, that animation works fine, but when it gets to the block where spoken == 1 that animation does not play it sets the image but it does not play the animation. Ive been looking around forever, I tried to run it on the main thread and a bunch of other things.

EDIT:

I have this method which is the animation right before the animation above that will not play unless set animationRepeatCount to 0, and if I set this animation to anything but 0 then the animation above plays but then this animation doesn't play. In this method I have animation repeat count to 16 and then the above animation works but this one doesn't. I would like to have this animation set to repeatCount 0 and when speech is done to fire the one above to repeatCount 1. Im very new to iOS and there is something I am just not getting right.

func handleSend(){
        if Thread.isMainThread{
            print("send on main thread")
        }else{
            print("send not on main thread")
        }
        do{
            try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
            try AVAudioSession.sharedInstance().setActive(true)

        }catch{}
        //UIView.animate(withDuration: 4.0, animations: {
            //animation 2
            print("second animation")
            self.imageView.stopAnimating()
            self.imageView.image = self.talkingImages.last
            self.imageView.animationImages = self.talkingImages
            self.imageView.animationDuration = 0.25
            self.imageView.animationRepeatCount = 16
            self.imageView.startAnimating()
            print("should have animated")


        //})
        let utterance = AVSpeechUtterance(string: self.finalString)
        //utterance.voice = AVSpeechSynthesisVoice(language: "en-GB")
        //utterance.rate = 0.1


        self.synthesizer.speak(utterance)

    }

EDIT2: I am posting the whole viewController just for reference, and it won't let me because it exceeds the character limit, but ill post all of the animations and explain the flow

this is the touchended override method for touching the image view, it is also where the first animation starts.

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {


        timesRubbed += 1
        if timesRubbed == 1{
            player?.stop()
            //Toast(text: keepRubbing).show()
            self.view.makeToast(keepRubbing, duration: 3.0, position: .top)
        }
        if timesRubbed == 2{
            player?.stop()
            //Toast(text: keepAgain).show()
            self.view.makeToast(keepAgain, duration: 3.0, position: .top)
        }
        if timesRubbed == 3{
            player?.stop()
            timesRubbed += 1
            playSoundComeOut()
            CATransaction.begin()
            CATransaction.setCompletionBlock {
                print("after animation 1")
                DispatchQueue.main.async {
                    CATransaction.begin()
                    CATransaction.setCompletionBlock{
                        print("after circle animation")
                            //UIView.animate(withDuration: 3.0, animations: {
                                //animation 2
                                print("second animation")
                                //self.imageView.stopAnimating()
                                self.imageView.image = self.talkingImages.last
                                self.imageView.animationImages = self.talkingImages
                                self.imageView.animationDuration = 0.25
                                self.imageView.animationRepeatCount = 0
                                self.imageView.startAnimating()
                                print("should have animated")


                            //})
                        let utterance = AVSpeechUtterance(string: self.greeting)
                        //utterance.voice = AVSpeechSynthesisVoice(language: "en-GB")
                        //utterance.rate = 0.1


                        self.synthesizer.speak(utterance)
                            //CATransaction.commit()

                    }
                //UIView.animate(withDuration: 3.0, animations: {
                    //animation 2
                    print("second animation")
                    self.imageView.stopAnimating()
                    self.imageView.image = self.circleImages.last
                    self.imageView.animationImages = self.circleImages
                    self.imageView.animationDuration = 1.5
                    self.imageView.animationRepeatCount = 2
                    self.imageView.startAnimating()
                    print("should have animated")

                //})
                    CATransaction.commit()
                }

            }
                  //UIView.animate(withDuration: 6.0, animations: {
                            //animation 1
                    if self.imageView.isFocused{
                        print("imageview is focused")
                    }else{
                        print("not focused")
                    }
                            self.imageView.image = self.comingOutImages.last
                            self.imageView.animationImages = self.comingOutImages
                            self.imageView.animationDuration = 6.0
                            self.imageView.animationRepeatCount = 1
                            self.imageView.startAnimating()
        //                })
            CATransaction.commit()        }


    }

then at the end of that animation sequence it goes to the speechSynthesizer method where spoken == 0 then it does the handleSend() method posted above and then it goes back to the speechSynthesizer method above where spoken == 1

If you need any more information please let me know

JRowan
  • 6,520
  • 6
  • 34
  • 57
  • 1
    It doesn't look good that you use both UIView animation block and CATransaction. Try again without the UIView animation block and set your duration on the CATransaction. – Vlad Rusu Mar 20 '20 at 01:33
  • no it still doesn't work, I took out the UIView animation block and put CATransaction.setAnimationDuration(6.0) before the ImageView stuff – JRowan Mar 20 '20 at 01:43
  • Don't use any CATransaction stuff. You can use UIView.animate and there is a version of it that has a completion block. Also, be sure to be running your animation on the main thread like in the following link: https://stackoverflow.com/a/24985766/10058854 – Alan S Mar 20 '20 at 12:18
  • I tried without CATransaction and doing it on main thread and it still does not work – JRowan Mar 20 '20 at 14:12
  • when I change animation repeat count to 0 it works but it repeats forever. I am trying to only have the animation play once – JRowan Mar 20 '20 at 14:16
  • in your `if spoken == 1` block, you don't call `stopAnimation()` before calling `startAnimation()` again. if you add `stopAnimation()` (like in your spoken == 0 block), does it make a difference? – bunnyhero Mar 26 '20 at 19:16
  • @bunnyhero not it doesn't make a difference.i tried that and I just didn't post it – JRowan Mar 27 '20 at 00:59
  • to be clear, the animation in spoken == 1 will not play unless I either set its repeat count to 0 or the animation before it cannot have animationrepeatcount 0, and I need the exact opposite of that – JRowan Mar 27 '20 at 21:37

1 Answers1

2

I ended up doing this for the last animation and it worked

self.imageView.stopAnimating()
                self.imageView.image = self.goingInImages.last
                self.imageView.layer.removeAllAnimations()
                let animation = CAKeyframeAnimation(keyPath: #keyPath(CALayer.contents))
                animation.values = self.goingInImages.map {$0.cgImage!}
                //animation.keyTimes = [0.0, 0.25, 0.5, 0.75, 1.0]
                animation.calculationMode = .discrete
                animation.duration = 6.0
                animation.repeatCount = 1
                self.imageView.layer.add(animation, forKey: nil)
JRowan
  • 6,520
  • 6
  • 34
  • 57