swiftanimationnslayoutconstraint

Animation is not showing as expected in swift


I have taken image and I want flyView to be drop from top middle to 200 from top and vanishes. for that tried like this

code: here I have given constraints for flyView as flyView.centerXAnchor and flyView.topAnchor then why flyView coming inside from left of the screen?? and when animation happening then why whole screen moves badly. i have clear tableview and below submit button as well but whole screen moving with animation why? how to fix this? please guide me.

class TableAnimationViewController: UIViewController {

@IBOutlet weak var tableView: UITableView!

let flyView = UIImageView()
override func viewDidLoad() {
    super.viewDidLoad()
    tableView.delegate = self
    tableView.dataSource = self
    
    self.flyView.image = UIImage(named: "offer_img")
    self.view.addSubview(flyView)
    
    self.flyView.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        flyView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 50),
        flyView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
        flyView.widthAnchor.constraint(equalToConstant: 100),
        flyView.heightAnchor.constraint(equalToConstant: 100)
    ])
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    UIView.animate(withDuration: 5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: [.curveEaseOut, .repeat], animations: { [self] in
        flyView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 200).isActive = true
        flyView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
        flyView.alpha = 0
        self.view.layoutIfNeeded()
    })
}
}

o/p

enter image description here


Solution

  • Your code has a number of issues.

    I created a project based on your code that works. Here is what the view controller code looks like:

    class ViewController: UIViewController {
        
        @IBOutlet weak var animateButton: UIButton!
        
        var topAnchor: NSLayoutConstraint? = nil
        let flyView = UIImageView()
        override func viewDidLoad() {
            super.viewDidLoad()
            
            self.flyView.image = UIImage(named: "Scampers")
            self.flyView.translatesAutoresizingMaskIntoConstraints = false
            self.view.addSubview(flyView)
            
            topAnchor = flyView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 50)
            NSLayoutConstraint.activate([
                topAnchor!,
                flyView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
                flyView.widthAnchor.constraint(equalToConstant: 100),
                flyView.heightAnchor.constraint(equalToConstant: 100)
            ])
        }
        
        @IBAction func handleAnimateButton(_ sender: UIButton?) {
            animateButton?.isEnabled = false
            UIView.animate(withDuration: 2, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: [.curveEaseOut, .repeat], animations: { [self] in
                topAnchor?.constant = 200
                flyView.alpha = 0
                self.view.layoutIfNeeded()
            })
        }
        override func viewDidAppear(_ animated: Bool) {
            //handleAnimateButton(nil)
        }
    }
    

    (I pulled out the animation into a button action, and also showed that you could call the animation code from viewDidAppear(_:) if desired.)

    I don't know of a way to include spring damping in UIView keyframe animations. I'd probably drop down to the lower-level CAAnimation and create an animation group that included a spring animation and a fade animation. That would work, but Core Animation is a lot fussier and harder to figure out than UIView animation.

    Note that there's not much point to having a spring animation and setting the Alpha to 0 at the same time. The image view fades away before the sprint animation is visible.

    You might want to instead create a keyframe animation that first does the animate down and then the fade animation.

    I had to use my own image for the FlyView, but below is what the animation looks like.

    Edit:

    If you refactor your animation code to use keyframe animations that might look something like this:

    @IBAction func handleAnimateButton(_ sender: UIButton?) {
        animateButton?.isEnabled = false
        UIView.animateKeyframes(withDuration: 1, delay: 0,
                                options: [UIView.KeyframeAnimationOptions(rawValue:  UIView.AnimationOptions.curveEaseOut.rawValue), .repeat]) {
            UIView.addKeyframe(withRelativeStartTime:0, relativeDuration: 0.75 ) {[self] in
                topAnchor?.constant = 200
                self.view.layoutIfNeeded()
            }
            UIView.addKeyframe(withRelativeStartTime:0.75, relativeDuration: 0.25 ) {[self] in
                flyView.alpha = 0
            }
        }
    }
    

    (Keyframe animations actually do support animation curves like ease in, ease out, and ease in/out, but the constants aren't defined, so you have to play games with raw values in order to use them.)

    enter image description here