Search code examples
swiftanimationuiimageviewcore-animation

Swift is completely ignoring the animation for UIImageView


Animation is simply not working. Image is added to screen, but not animated. The image in the code is normally not added in the viewDidAppear function, this was just to test. Still did not help...

Below function is in a ViewController that is loaded in a PageViewController.

override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let image = UIImage.fontAwesomeIcon(
            name: .bell,
            style: .solid,
            textColor: .white,
            size: CGSize(width: 100, height: 100)
        )

        let imageView = Init(UIImageView(frame: CGRect.zero)) {
            $0.contentMode = .scaleAspectFit
            $0.translatesAutoresizingMaskIntoConstraints = false
            $0.image = image

        }
        self.view.addSubview(imageView)

        let animation = CABasicAnimation(keyPath: "transform.rotation")
        animation.repeatCount = .infinity
        animation.duration = 7
        animation.fromValue = 0.0
        animation.toValue = -Double.pi * 2
        imageView.layer.add(animation, forKey: nil)

    }

I tried different animations but not a single animation worked. Please help....

EDIT1

let animation = CABasicAnimation(keyPath: "position")
        animation.repeatCount = .infinity
        animation.duration = 7
        animation.autoreverses = true
        animation.fromValue = NSValue(cgPoint: CGPoint.init(x: imageView.center.x - 10, y: imageView.center.y))
        animation.toValue = NSValue(cgPoint: CGPoint.init(x: imageView.center.x + 10, y: imageView.center.y))
        imageView.layer.add(animation, forKey: "position.x")

EDIT2: this does not work either:


    var imageView: UIImageView?

    override viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let keyFrame = CAKeyframeAnimation(keyPath: "position")
        let point = image!.layer.position
        keyFrame.values = [NSValue(cgPoint: CGPoint(x: CGFloat(point.x), y: CGFloat(point.y))),
                           NSValue(cgPoint: CGPoint(x: CGFloat(point.x - 10), y: CGFloat(point.y))),
                           NSValue(cgPoint: CGPoint(x: CGFloat(point.x + 10), y: CGFloat(point.y))),
                           NSValue(cgPoint: CGPoint(x: CGFloat(point.x - 10), y: CGFloat(point.y))),
                           NSValue(cgPoint: CGPoint(x: CGFloat(point.x + 10), y: CGFloat(point.y))),
                           NSValue(cgPoint: CGPoint(x: CGFloat(point.x - 10), y: CGFloat(point.y))),
                           NSValue(cgPoint: CGPoint(x: CGFloat(point.x + 10), y: CGFloat(point.y))),
                           NSValue(cgPoint: point)]
        keyFrame.repeatCount = .infinity
        keyFrame.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
        keyFrame.duration = 0.7
        image!.layer.position = point

        image!.layer.add(keyFrame, forKey: keyFrame.keyPath)

    }

    override func loadView() {

        var image = UIImage.fontAwesomeIcon(
            name: .bell,
            style: .solid,
            textColor: .white,
            size: CGSize(width: 2000, height: 2000)
        )

        imageView = Init(UIImageView(frame: CGRect.zero)) {
            $0.contentMode = .scaleAspectFit
            $0.translatesAutoresizingMaskIntoConstraints = false
            $0.image = image

        }
        self.view.addSubview(imageView!)

    }

Solution

  • ok, turns out the viewDidAppear is running TOO early and thus the animation is not being set. Setting it up like this solved it. Dispatch animation after 1 sec. Even half a second was ok. Just cannot be run immediately.

    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
        // animation here
    }
    

    Pretty weird if you ask me, but whatever works.

    So, no idea why I cannot run an animation directly in viewDidAppear, even when the UIView item is set up during LoadView. But this workaround helps.