Constraints resets when app is going in background - iOS 13

Viewed 3206

I have set a view's leading, trailing constraints normally. I have set its height to static 325. And for bottom constraint I have set 2 constraints 1. with main view's bottom constraint to view's bottom constraint. 2. with main view's bottom constraint to view's top constraint. Now on user's action I just show hide view with animation. So when view gets displayed on the screen and the app goes in background then the view's constraint automatically gets altered and the view gets hidden. This issue is only occurring in iOS 13 devices.

I tried to update its constraints on viewWillAppear() but in iOS 13 the viewWillAppear of ViewControllers is also not called when app is activated from background. Also I don't think , that this is a good idea to update constraints.

Storyboard

Class File

class ViewController: UIViewController {

    @IBOutlet weak var topConstraint: NSLayoutConstraint!
    @IBOutlet weak var bottomConstraint: NSLayoutConstraint!

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

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) {
            self.topConstraint.isActive = false
            self.bottomConstraint.isActive = true
            UIView.animate(withDuration: 0.3) {
                self.view.layoutIfNeeded()
            }
        }
    }
}

I don't want my constraints to be changed or updated when app state changes from foreground to background and vice versa.

Please help me with the same.

TIA

7 Answers

Also met this issue. Noticed that constraints keep reseting in case if they are not checked Installed in Interface Builder. So, as workaround keep all constraints Installed in IB and change isActive state just in code.

enter image description here

I found the issue is happening only in iOS 13.0 and above, Please try to make the constraint changes in ViewDidLayoutSubviews

      override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
            self.bottomConstraint.isActive = false
            self.topConstraint.isActive = true
    self.view.layoutIfNeeded()
}

The workaround that worked for me was to listen for UIApplication.willEnterForegroundNotification, and set isActive on all constraints at this point.

This notification seems to be published after the system (incorrectly) resets all constraints to their IB states, and before the app becomes visible again. So it's the perfect time to fix the constraints.

One caveat: when your constraints are contained in an autosizing table view cell, this notification seems to be triggered after the system calculates the height of the cell. So, you will need to trigger the table view to recalculate cell heights after updating your constraints (see this question for info on how to do that).

You can achieve the solution using setting the priority and flipping the values.

 if !isShowing{
       self.bottomConstraint.priority = UILayoutPriority(rawValue: 250)
       self.topConstraint.priority = UILayoutPriority(rawValue: 750)
   }else{
       self.bottomConstraint.priority = UILayoutPriority(rawValue: 750)
       self.topConstraint.priority = UILayoutPriority(rawValue: 200)
   }
   isShowing = !isShowing
   self.subview.layoutIfNeeded()

if you need to know "how can i inform when the apps comes background to foreground". You should use NotificationCenter to send a signal to all. But this is a not good practise.

Maybe you can tell your aim, and we can give you differ approach.

I also had a similar problem whenever I try to update the constant of a constraint that have variations set on storyboard. To solve this, simply delete all variations and set them programmatically.

Variation screenshot

Well I got the solution. Actually, we can’t say it the solution. I just run the same code in iOS 13.1 or higher version devices and the issue was gone. So for now I can say this issue only occurs in iOS 13.0.

Related