4

I am trying to get a view to animate from the centre of the screen, to leave the screen after 1 second when the view loads.

The problem I am having is that after a millisecond of the view being in the original (correct) position upon loading, it then snaps to the new position and animates back to the original position.

I have the following code in viewDidLoad

override func viewDidAppear(animated: Bool) {

    UIView.animateWithDuration(0.7, delay: 1, options: .CurveEaseOut, animations: {
        var loadingViewFrame = self.loadingView.frame
        loadingViewFrame.origin.y += 600

        self.loadingView.frame = loadingViewFrame
        }, completion: { finished in
            print("moved")
    })


}

I have tried putting this code in a button action and it works fine, so is there some other method I should be using when animating on viewWillAppear or is there something else I have missed?

I have removed all autolayout constraints because I read that they may cause some problems.

I also have other code in viewDidAppear as well as viewWillAppear and viewDidLoad which I could show here if you think it is useful, but I have commented out all of this code to leave with only the basic code and the same error is still occurring.

Thanks a lot for your help.


Edit 1

I have moved the code to viewDidLayoutSubviews and have used dispatch_once to ensure it is only done once. The image still animates from the new position to the original position, but now the image is not located in the original position for a millisecond upon loading.

This is the code I have added

    var token: dispatch_once_t = 0

override func viewDidLayoutSubviews() {
    dispatch_once(&token) {

        UIView.animateWithDuration(0.7, delay: 1, options: .CurveEaseOut, animations: {
            var loadingViewFrame = self.loadingView.frame
            loadingViewFrame.origin.x += 600

            self.loadingView.frame = loadingViewFrame
            }, completion: { finished in
                print("moved")
        })
    }
}
Jon Buckley
  • 117
  • 1
  • 12

1 Answers1

4

First off, you need to call super.viewDidAppear(animated) when you override viewDidAppear: in your view controller subclass.

Unfortunately, it seems to work just fine for me with this view controller so there must be something else going on...

class ViewController: UITableViewController {
    var loadingView: UIView!

    override func viewDidLoad() {
            super.viewDidLoad()

        loadingView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
        loadingView.backgroundColor = UIColor.redColor()
        loadingView.center = view.center
        view.addSubview(loadingView)
    }

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

        UIView.animateWithDuration(0.7, delay: 1, options: .CurveEaseOut, animations: {
            var loadingViewFrame = self.loadingView.frame
            loadingViewFrame.origin.y += 600

            self.loadingView.frame = loadingViewFrame
        }, completion: nil)
    }
}

Your issue is most-likely because layoutSubviews may be called after viewDidAppear: (I believe this is different for iOS 8 vs iOS 9) so the changes you made get overridden almost immediately. You can confirm this by overriding viewDidLayoutSubviews in your UIViewController subclass and breakpointing viewDidLoad, viewWillAppear:, viewDidAppear:, and viewDidLayoutSubviews to see what order they happen in.

One thing you can do to achieve a similar effect is use a dispatch_once block with a once_token that is a property of your class to execute the animation in viewDidLayoutSubviews. This will insure that your animation is executed once per instance of your class after the initial view layout has occurred. This might be what you're looking for.

If you could provide more of your view controller code or a github link I may be able to give you a better, less potentially hacky, answer about what is going on.

  • Thanks a lot for your reply. I actually tried putting the animation code in `viewDidLayoutSubviews` before but it got called several times and got very jittery. Now I have added in the `dispatch_once` as you suggested it does it only once, but it is still from the new position to the original position, however it no longer has the short time at the beginning where it is in the correct position. – Jon Buckley Jan 03 '16 at 06:57
  • I am still pretty new to swift and coding in general so I will update the original question with the code I have added to `viewDidLayoutSubviews`. Please let me know if I have done anything wrong with that, and what else may be causing this issue if not. Thanks – Jon Buckley Jan 03 '16 at 06:58
  • What I have done now is set the original position off the screen so that the image starts in the original position but what should be the new position (on the screen) and animates to what should be the new position but what is coded as the original position (off the screen)...if that makes sense. – Jon Buckley Jan 03 '16 at 07:46
  • This seems like a horrible way of doing it though, and I can see it causing problems further down the line. What do you think? There must be a better way of doing it. Any suggestions would be much appreciated – Jon Buckley Jan 03 '16 at 07:47
  • Yes this definite could contribute to problems down the road if you aren't careful. Generally you probably don't want to do much in viewDidLayoutSubviews because it can be called many time. I was just suggesting a tactic you **could** use to get something to happen once when a view comes on screen for the first time. I might have lead you astray because it was late at night and I wasn't able to open xcode. Your issue might simply be because you didn't call `super.viewDidAppear` in your method. I'm going to try it myself and see if I can get a better solution for you. – jhildensperger Jan 04 '16 at 00:04
  • Great. Thanks a lot. I look forward to your response :) – Jon Buckley Jan 04 '16 at 02:49
  • Hi again @jhildensperger. Have you had a chance to find a better solution then my messy way yet? I have had a play with it but haven't been able to work anything correctly. I can give you more code from the pages if you think it would be helpful. Thanks – Jon Buckley Jan 10 '16 at 03:14