4

I'm trying to change the position of a separate View at launch of the app via the viewDidLoad using this code:

let xPosition = dynView.frame.origin.x - 100

    //View will slide view
    let yPosition = dynView.frame.origin.y;

    let height = dynView.frame.size.height
    let width = dynView.frame.size.width

    UIView.animate(withDuration: 1.0, animations: {

        self.dynView.frame = CGRect(x: xPosition, y: yPosition, width: width, height: height)


    })

However, this doesn't seem to work directly in the viewDidLoad the code works if I assign to to a button using a @IBAction

I'm guessing I'm missing something here, but I can't figure out what.

Mr Riksson
  • 560
  • 3
  • 10
  • 29

1 Answers1

5

Referring to your answer -in the comments- about using constraints:

Yes, I do. I'm assuming this has something to do with it? Is the constraints loaded after the viewDidLoad?

That's right, from viewDidLoad() documentation:

Called after the controller's view is loaded into memory.

Nothing to do with checking that the setup of constraints have been done (subviews laid out).

If I'm not mistaking, what are you looking for is the viewDidLayoutSubviews() method:

Called to notify the view controller that its view has just laid out its subviews.

Your view controller can override this method to make changes after the view lays out its subviews. The default implementation of this method does nothing.

So, instead of implementing the code of changing the y position of the view in the viewDidLoad() try to let it in the viewDidLayoutSubviews(), as follows:

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

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    let xPosition = dynView.frame.origin.x - 100
    let yPosition = dynView.frame.origin.y

    let height = dynView.frame.size.height
    let width = dynView.frame.size.width

    UIView.animate(withDuration: 1.0, animations: {
        self.dynView.frame = CGRect(x: xPosition, y: yPosition, width: width, height: height)
    })
}

ALSO: If you don't want to let the animation to be repeated after popping/dismissing the next ViewController, you can declare a flag property for determining to start the animation or not, similar to:

var isAnimated = false

    override func viewDidLayoutSubviews() {
        if isAnimated == false {
            super.viewDidLayoutSubviews()

            UIView.animate(withDuration: 1.0, animations: {
                self.btn.frame.origin.y = 20
            }, completion: { _ in
                self.isAnimated = true
            })
        }
    }

Additional Note:

I recommend changing the value of constraints instead of directly change the frame size/origin. You might want to check this question/answer.

Ahmad F
  • 30,560
  • 17
  • 97
  • 143
  • Don't you think that viewDidLayoutSubviews method is a bad place to update UI? * viewDidLayoutSubviews will get called multiple times in the view's lifecycle such as, orientation change or moving in and out of another view. – 3li Dec 26 '16 at 11:30
  • @3li If your intention to update components frame, you should NOT do this in `viewDidLoad()` I suggest to check [this article](http://www.iosinsight.com/override-viewdidlayoutsubviews/), it is clear and simple. – Ahmad F Dec 26 '16 at 12:44