0

I have 4 buttons, all use the same animate func

  • imageViewWithoutDelay
  • imageViewWithDelay
  • ViewWithoutDelay
  • ViewWithDelay

my code:

import UIKit

class ViewController: UIViewController {

    @IBAction func imageViewithoutDelay(_ sender: AnyObject) {
        let circleImage = UIImageView()
        // kindly add your own image.
        circleImage.image = UIImage(named: "empty")
        animate(inputView: circleImage, delay: false)
    }

    @IBAction func imageViewWithDelay(_ sender: UIButton) {

        let circleImage = UIImageView()
        circleImage.image = UIImage(named: "empty")
        animate(inputView: circleImage, delay: true)
    }

    func animate(inputView : UIView, delay: Bool){

        inputView.layer.cornerRadius = inputView.frame.size.width / 2
        inputView.clipsToBounds = true
        inputView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(inputView)

        let screenSize = UIScreen.main.bounds
        let screenHeight = screenSize.height * 0.10
        inputView.center.y = screenHeight
        view.setNeedsLayout()
        view.setNeedsDisplay()

        if delay == true{
        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: {
            UIView.animate(withDuration: 2.5, animations: {
                inputView.alpha = 0.0
                let screenSize = UIScreen.main.bounds
                let screenHeight = screenSize.height * 0.10
                inputView.center.y -= screenHeight
            })
        })} else{
            UIView.animate(withDuration: 2.5, animations: {
                inputView.alpha = 0.0
                let screenSize = UIScreen.main.bounds
                let screenHeight = screenSize.height * 0.10
                inputView.center.y -= screenHeight
            })

        }

    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

What amuses me is the different behavior of the UIview & UIImageView.

The UIImageView instance only animates as intended (going up from origin) if I use delay. However, without using a delay block, UIImageView instance first drops down, then animates going up to its origin).

The UIView doesn’t show different behaviors. It animates from its origin and goes up.

enter image description here Is this a bug?

This question is a tangent to this original question.

Community
  • 1
  • 1
Honey
  • 24,125
  • 14
  • 123
  • 212

1 Answers1

1

What you're doing is wrong no matter how you slice it. You cannot add a view and animate it all in the same breath. You can only animate a view that is already in the interface.

That is why it works for the image view if you add the delay: by the time you animate, the image view has gotten into the interface and the interface has settled down.

The fact that it seems to work for the non-imageview is just dumb luck.

matt
  • 447,615
  • 74
  • 748
  • 977
  • I see. 1. by the time it gets to the animation line, isn't it already in the interface? 2. why does it happen this way? I mean why does it shift? Shouldn't there be a reason of why it can't happen and why it can for imageView. – Honey Feb 10 '17 at 21:21
  • I don't know why it works for the non-imageview. — It isn't "in the interface" until the runloop has a chance to cycle. Even a delay of zero should be enough, because you'll come back in on the main thread on the next runloop. Try it on your image view and see. – matt Feb 10 '17 at 21:25
  • You mean change to `.seconds(0)`? I did that, and now both my imageViews drop down then animate up to origin. I also tried `.nanoseconds(1)` and still got same incorrect result. – Honey Feb 10 '17 at 21:30
  • Maybe it gets optimized away. I was thinking use `DispatchQueue.async {...}` instead of your `asyncAfter`. Or use my [`delay` utility](http://stackoverflow.com/a/24318861/341994) and try `delay(0)` — but if that doesn't work, try something like `delay(.01)`. Let's see what you find out... – matt Feb 10 '17 at 21:43