skip to Main Content

I want to show an animation after the my OnboardingController with container – Page with image view is opened. I use this code for to do it, but the animation doesn’t work in my app:

My code in ViewController class:

class ViewController: UIViewController {
    
    lazy var button: UIButton = {
        let button = UIButton()
        button.backgroundColor = .darkGray
        button.translatesAutoresizingMaskIntoConstraints = false
        button.addTarget(self, action: #selector(setupViews), for: .touchUpInside)
        return button
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(button)
        button.frame = CGRect(x: 400, y: 100, width: 100, height: 50)
    }
    
    @objc func setupViews() {
        let detailController = OnboardingController()
        self.present(detailController, animated: true, completion: nil)
    }
    
}

My code in OnboardingController class:

class OnboardingController: UIViewController {
    
    let container: UIView = {
        let view = UIView()
        view.backgroundColor = .blue
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    let views: Page = {
        let view = Page()
        view.backgroundColor = .red
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
        
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(container)
        container.addSubview(views)
        
        container.topAnchor.constraint(equalTo: view.topAnchor, constant: 0.0).isActive = true
        container.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0.0).isActive = true
        container.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0).isActive = true
        container.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0.0).isActive = true

        views.topAnchor.constraint(equalTo: container.topAnchor).isActive = true
        views.bottomAnchor.constraint(equalTo: container.bottomAnchor).isActive = true
        views.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
        views.trailingAnchor.constraint(equalTo: container.trailingAnchor).isActive = true
    }
    
}

My code in Page class:

class Page: UIView {
        
    private let imageView: UIImageView = {
        let image = UIImageView()
        image.image = UIImage(named: "1")
        image.translatesAutoresizingMaskIntoConstraints = false
        return image
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        addSubview(imageView)
        
        imageView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        imageView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        imageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: -120).isActive = true
        imageView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0).isActive = true
        
        self.imageView.transform = CGAffineTransformTranslate(.identity, 0, 0)
        UIView.animate(withDuration: 7.0, delay: 0, animations: {
            self.imageView.transform = CGAffineTransformTranslate(.identity, 120, 0)
        }, completion: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("error")
    }
}

How to solve this problem?

2

Answers


  1. Animations will not work in init since view is not added to window or view hierarchy yet.

    Try adding your animation code in didMoveToSuperview or layoutSubviews. Also if you are using layoutSubviews make sure animations are triggered only once using a flag maybe.

    Example:

    override func didMoveToSuperview() {
        super.didMoveToSuperview()
        if superview != nil {
            self.imageView.transform = CGAffineTransformTranslate(.identity, 0, 0)
            UIView.animate(withDuration: 7.0, delay: 0, animations: {
                self.imageView.transform = CGAffineTransformTranslate(.identity, 120, 0)
            }, completion: nil)
        }
    }
    
    Login or Signup to reply.
  2. I recommend controlling the animation from its superview life cycle, in this case is OnboardingController, and viewDidAppear is the best option in this situation. It should look like:

    class Page: UIView {
        ...
        func startAnimation() {
            self.imageView.transform = CGAffineTransformTranslate(.identity, 0, 0)
            UIView.animate(withDuration: 7.0, delay: 0, animations: {
                self.imageView.transform = CGAffineTransformTranslate(.identity, 120, 0)
            }, completion: nil)
        }
    }
    

    And manage Page state by:

    class OnboardingController: UIViewController {
        private var isAnimatedPage = false
        
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            if !isAnimatedPage {
                isAnimatedPage = true
                views.startAnimation()
            }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search