Animations - frozen view top left corner

Hello everybody,


I have an animation to create ballons floating from the bottom to the top of the screen. Despite producing the behaviour I want, at some point, when the ballons are floating upwards the objectView I am using one ballon gets printed at the top left corner of the screen and does not move or disappear.


Has this ever happend to any of you?


func presentVictoryView(word: String) {

        blackView.isHidden = false
        
        for _ in 0 ... 30 {
            
            let objectView = UIView()
            objectView.translatesAutoresizingMaskIntoConstraints = false
            objectView.frame = CGRect(x: 0, y: 0, width: 20, height: 100)
            objectView.backgroundColor = .clear
            //objectView.alpha = CGFloat(0.9)
            objectView.isHidden = false
            
            let ballon = UILabel()
            ballon.translatesAutoresizingMaskIntoConstraints = false
            ballon.frame = CGRect(x: 0, y: 0, width: 20, height: 100)
            ballon.backgroundColor = .clear
            //ballon.alpha = CGFloat(0.9)
            ballon.text = ""
            ballon.font = UIFont.systemFont(ofSize: 60)
            objectView.addSubview(ballon)
            
            NSLayoutConstraint.activate([
                ballon.centerXAnchor.constraint(equalTo: objectView.centerXAnchor),
                ballon.centerYAnchor.constraint(equalTo: objectView.centerYAnchor)
            ])
            
            blackView.addSubview(objectView)
            
            let randomXOffset = Int.random(in: -120 ..< 200)
            
            let path = UIBezierPath()
            path.move(to: CGPoint(x: 160 + randomXOffset, y: 1000))
            path.addCurve(to: CGPoint(x: 100 + randomXOffset, y: -300), controlPoint1: CGPoint(x: 300 - randomXOffset, y: 600), controlPoint2: CGPoint(x: 70 + randomXOffset, y: 300))
            
            let animation = CAKeyframeAnimation(keyPath: "position")
            animation.path = path.cgPath
            animation.repeatCount = 1
            animation.duration = Double(arc4random_uniform(40) + 30) / 10
            //animation.timeOffset = Double(arc4random_uniform(50))
            
            objectView.layer.add(animation, forKey: "animate position along path")
        }

        newGame()
    }

I have tried a lot of things... I don't know what I am doing wrong...


Thank you!

at some point,

When precisely ?


when the ballons are floating upwards the objectView I am using one ballon gets printed at the top left corner of the screen and does not move or disappear.

gets printed: do you mean it is displayed here ?

Which balloon ?

Only one or several ?


Note: tehre is a better way now to generate random line 39

Double(Int.random(in: 0...40) + 30) / 10


I understand you want a value between 3 and 7 at the end ?

So directly

Double.random(in: 3.0 ... 7.0))

This happens in the middle of the animation... And, as a result it just stays there. It just happens with one ballon.


Here is a video of it happening:


https://imgur.com/a/tyS0Q5u

This happens in the middle of the animation... And, as a result it just stays there. It just happens with one ballon.

Always the same ? Which one ? The last ?

It is always the same thing. i have one reply to this post being moderated where I provide a vídeo.


Image the ballons floating from bottom to top. In the middle of the animation one ballon appears on the top left corner and stays there fixed... It always happens the same way.

Edit the link as h ttps:

Could you set. label on ballons, to visualize which one it is precisely ?

I have https://...

Hi tmsm1999,

the position in the top left corner is the actual frame you specified for your view. Adding a CAAnimation to a view doesn't change a views frame. It only changes the position while the animation is running. Therefore, as soon as the animation is finished your views jump to that original position in the top-left.

What you can do in your case is to simply move that view out of bounds. Remember however, that you need to remove your views from the view hierarchy after the animation finishes.

You may also want to take a look at UIViewPropertyAnimator which simplifies creating animations. For this specific effect, you may also check out CAEmitterLayer, it's a special layer designed to build such effects efficiently even with hundreds of objects.

Here's a working version of your example:
Code Block swift
func presentVictoryView() {
    for _ in 0 ... 30 {
        let objectView = UIView()
        objectView.frame = CGRect(x: 0, y: -100, width: 100, height: 100)
        objectView.backgroundColor = .clear
        objectView.isHidden = false
        let ballon = UILabel()
        ballon.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
        ballon.backgroundColor = .clear
        ballon.text = "🎈"
        ballon.font = UIFont.systemFont(ofSize: 60)
        objectView.addSubview(ballon)
        blackView.addSubview(objectView)
        let randomXOffset = Int.random(in: -120 ..< 200)
        let path = UIBezierPath()
        path.move(to: CGPoint(x: 160 + randomXOffset, y: 1000))
        path.addCurve(to: CGPoint(x: 100 + randomXOffset, y: -300), controlPoint1: CGPoint(x: 300 - randomXOffset, y: 600), controlPoint2: CGPoint(x: 70 + randomXOffset, y: 300))
        let animation = CAKeyframeAnimation(keyPath: "position")
        animation.path = path.cgPath
        animation.repeatCount = 1
        animation.duration = Double(arc4random_uniform(40) + 30) / 10
        CATransaction.begin()
        CATransaction.setCompletionBlock {
           objectView.removeFromSuperview()
        }
        objectView.layer.add(animation, forKey: "animate position along path")
        CATransaction.commit()
    }
}


Animations - frozen view top left corner
 
 
Q