Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
777 views
in Technique[技术] by (71.8m points)

ios - Consecutive Animation Calls Not Working

I have a button that calls an animateWithDuration code that fades an image out, fades text & a new bg color in , and then resets back to normal. The animation takes a few seconds to complete and works great.

However! There's a problem:

Sometimes this button will be pushed again before the animation finishes. When this happens, I want the current animate to stop and start over again.

Researched Solution Not Working

According to my reading, the solution should be simple, just import QuartzCore and add:

button.layer.removeAllAnimations()

This does remove the animation but the new/second animation is totally messed up. The image that is supposed to be hidden isn't, the text never shows up, and the color transition is all wrong. What's happening!?!

//Animate Finished feedback in footer bar
func animateFinished(textToDisplay: String, footerBtn: UIButton, footerImg: UIImageView) {

    //Should cancel any current animation
    footerBtn.layer.removeAllAnimations()

    footerBtn.alpha = 0
    footerBtn.setTitle(textToDisplay, forState: UIControlState.Normal)
    footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Regular", size: 18)
    footerBtn.setTitleColor(UIColor(red: 255/255.0, green: 255/255.0, blue: 255/255.0, alpha: 1.0), forState: UIControlState.Normal)
    footerBtn.backgroundColor = UIColor(red: 217/255.0, green: 217/255.0, blue: 217/255.0, alpha: 1.0)

    UIView.animateWithDuration(0.5, delay: 0.0, options: nil, animations: {
        footerImg.alpha = 0.01 //Img fades out
        footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 163/255.0, blue: 00/255.0, alpha: 0.6)
        }
        , completion: { finished in

            UIView.animateWithDuration(0.5, delay: 0.0, options: nil, animations: {
                footerBtn.alpha = 1 //Text fades in
                footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 208/255.0, blue: 11/255.0, alpha: 0.6)
                }
                , completion: { finished in

                    UIView.animateWithDuration(0.5, delay: 1.0, options: nil, animations: {
                        footerBtn.alpha = 0.01 //Text fades out
                        footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 173/255.0, blue: 00/255.0, alpha: 0.6)
                        }
                        , completion: { finished in

                            UIView.animateWithDuration(0.5, delay: 0.0, options: nil, animations: {
                                footerImg.alpha = 1 //Img fades in
                                }
                                , completion: { finished in
                                    footerBtn.backgroundColor = UIColor.clearColor()
                                    footerBtn.setTitleColor(UIColor(red: 55/255.0, green: 55/255.0, blue: 55/255.0, alpha: 1.0), forState: UIControlState.Normal)
                                    footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Light", size: 18)
                                    footerBtn.setTitle("", forState: UIControlState.Normal)
                                    footerBtn.alpha = 1
                                    //Completion blocks sets values back to norm
                            })
                    })
            })
    })
}//End of animation

@Shripada suggested I switch to keyframes for more readable code. Keyframe format below. It did not solve the animation interruption problem. If you can solve the problem in nested or keyframe format, please post it!

func animateFinished(textToDisplay: String, footerBtn: UIButton, footerImg: UIImageView) {
    //Should cancel any current animation
    footerBtn.layer.removeAllAnimations()

    footerBtn.alpha = 0
    footerBtn.setTitle(textToDisplay, forState: UIControlState.Normal)
    footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Regular", size: 18)
    footerBtn.setTitleColor(UIColor(red: 255/255.0, green: 255/255.0, blue: 255/255.0, alpha: 1.0), forState: UIControlState.Normal)
    //footerBtn.backgroundColor = UIColor(red: 217/255.0, green: 217/255.0, blue: 217/255.0, alpha: 1.0)

    UIView.animateKeyframesWithDuration(3.0 /*Total*/, delay:0.0, options: UIViewKeyframeAnimationOptions.CalculationModeLinear, animations: {

            UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration:0.10, animations:{
                footerImg.alpha = 0.01 //Img fades out
                footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 103/255.0, blue: 00/255.0, alpha: 0.6) //Bg turns to green
            })

            UIView.addKeyframeWithRelativeStartTime(0.10, relativeDuration:0.30, animations:{
                footerBtn.alpha = 1 //Text and green bg fades in
                footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 173/255.0, blue: 11/255.0, alpha: 0.6) //BG turns greener
            })

            UIView.addKeyframeWithRelativeStartTime(0.40, relativeDuration:0.50, animations:{
                footerBtn.alpha = 0.01 //Text fades out & bg fade out
            })

        },
        completion: {  finished in
            footerImg.alpha = 1
            footerBtn.alpha = 1
            footerBtn.backgroundColor = UIColor.clearColor()
            footerBtn.setTitleColor(UIColor(red: 55/255.0, green: 55/255.0, blue: 55/255.0, alpha: 1.0), forState: UIControlState.Normal)
            footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Light", size: 18)
            footerBtn.setTitle("", forState: UIControlState.Normal)
            //Completion blocks sets values back to norm
        }
    )
}//End of 'Finished' animation
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I added some print lines to your animateFinished method, in order to see what's going on:

func animateFinished(textToDisplay: String, footerBtn: UIButton, footerImg: UIImageView) {
    //Should cancel any current animation
    print("Remove animations")
    footerBtn.layer.removeAllAnimations()
    print("Animations removed")

    footerBtn.alpha = 0
    footerBtn.setTitle(textToDisplay, forState: UIControlState.Normal)
    footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Regular", size: 18)
    footerBtn.setTitleColor(UIColor(red: 255/255.0, green: 255/255.0, blue: 255/255.0, alpha: 1.0), forState: UIControlState.Normal)
    //footerBtn.backgroundColor = UIColor(red: 217/255.0, green: 217/255.0, blue: 217/255.0, alpha: 1.0)
    print("Initial animation setup completed")

    UIView.animateKeyframesWithDuration(3.0 /*Total*/, delay:0.0, options: UIViewKeyframeAnimationOptions.CalculationModeLinear, animations: {

            UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration:0.10, animations:{
                footerImg.alpha = 0.01 //Img fades out
                footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 103/255.0, blue: 00/255.0, alpha: 0.6) //Bg turns to green
            })

            UIView.addKeyframeWithRelativeStartTime(0.10, relativeDuration:0.30, animations:{
                footerBtn.alpha = 1 //Text and green bg fades in
                footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 173/255.0, blue: 11/255.0, alpha: 0.6) //BG turns greener
            })

            UIView.addKeyframeWithRelativeStartTime(0.40, relativeDuration:0.50, animations:{
                footerBtn.alpha = 0.01 //Text fades out & bg fade out
            })

        },
        completion: {  finished in
            print("Completion block started")
            footerImg.alpha = 1
            footerBtn.alpha = 1
            footerBtn.backgroundColor = UIColor.clearColor()
            footerBtn.setTitleColor(UIColor(red: 55/255.0, green: 55/255.0, blue: 55/255.0, alpha: 1.0), forState: UIControlState.Normal)
            footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Light", size: 18)
            footerBtn.setTitle("", forState: UIControlState.Normal)
            //Completion blocks sets values back to norm
            print("Completion block finished")
        }
    )
}//End of 'Finished' animation

If you allow the animations to run to completion, the log shows, as you would expect:

Remove animations
Animations removed
Initial animation setup completed
Completion block started
Completion block finished

But if you tap the button during the animation, you see this:

Remove animations
Animations removed
Initial animation setup completed
Remove animations
Animations removed
Initial animation setup completed
Completion block started
Completion block finished
Completion block started
Completion block finished

What's happening it that the removeAllAnimations causes the completion block (for the first call) to be executed, after the initial setup for the second call is completed, but before the second animations are undertaken. So, for example, the button title is "" during the second animation.

The fix is relatively straight forward: don't execute the completion block if the animations have not finished:

        completion: {  finished in
            if (!finished) {
                return
            }
            print("Completion block started")
            footerImg.alpha = 1
            footerBtn.alpha = 1
            footerBtn.backgroundColor = UIColor.clearColor()
            footerBtn.setTitleColor(UIColor(red: 55/255.0, green: 55/255.0, blue: 55/255.0, alpha: 1.0), forState: UIControlState.Normal)
            footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Light", size: 18)
            footerBtn.setTitle("", forState: UIControlState.Normal)
            print("Completion block finished")
            //Completion blocks sets values back to norm
        }

Also, as per Shripada, you will need to remove animations from footerImg as well as footerBtn, with:

footerImg.layer.removeAllAnimations()

at the start of the method.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...