0

Hope all is well. Directly to the issue:

Environment : Version 11.6 / Swift 5

There is a basic view controller(TestViewController) embedded in UINavigationController. Say that this TestViewController has a button that's moving the self.view up by tapping. With the view moved up then leave the app(leaving it inactive or background whatever) and comeback(active again), the moved view is going back to y position 0, which means the view frame is going back to the CGRect(0, 0, yourViewWidth, yourViewHeight).

The repro is code only and no need for Storyboard.

First is a SceneDelegate that is initialising the navigation controller when launching, and printing the calling message in the console when app becomes active. Why I am thinking that it is happening with UINavigationController is that it is not with just UIViewController. You can test it out with commenting/uncommenting the initialising lines for the root view controller in the delegates:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        let window = UIWindow(windowScene: windowScene)
        window.makeKeyAndVisible()
        self.window = window
        window.rootViewController = UINavigationController(rootViewController: TestViewController())
/// Please try with normal view controller as below
//        let controller = TestViewController()
//        window.rootViewController = controller
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        print("sceneDidBecomeActive")
        // Called when the scene has moved from an inactive state to an active state.
        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
    }
}

Second and last part is even simpler. Have a look:

class TestViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let button = UIButton(frame: CGRect(x: view.frame.width/2, y: view.frame.height/2, width: 100, height: 100))
        button.setTitle("click", for: .normal)
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
        button.backgroundColor = .green
        view.addSubview(button)
    }
    
    @objc func buttonTapped() {
        view.frame.origin.y -= 200
    }
}

gifs.

enter image description here

enter image description here

Can anyone figure out why this is occurring? It might not be due to UINavigationController, so please teach me! Might it is a bug, or intended. No idea at all. Any advice will be highly appreciated!! Many thanks in advance:)

Matthew So
  • 75
  • 1
  • 2
  • 8
  • What you are doing is changing the position of your ViewController's view. Why not change the position of the button instead? My guess is that it's relaying out the view (not its content) after the scene becomes active again. – rs7 Aug 17 '20 at 10:51
  • @rs7 thank you for your comment. I need to move the view position for my real app. I want to move the view itself as keyboard shows/hides, as objects are anchored to the view. If I move respective objects it would be so hectic as there are a lot of it. – Matthew So Aug 17 '20 at 10:58
  • 1
    I would instead use a UIScrollView and change its contentInsets when the keyboard is showing. You'll need to add keyboard show/hide observers to achieve that. – rs7 Aug 17 '20 at 11:42
  • @rs7 Sounds great. I thought using a scroll view with sticky footer but contentInset. I will definitely try it. However the question posted itself still remained unsolved. Maybe it is intended and should avoid moving the view? – Matthew So Aug 17 '20 at 13:22
  • 1
    In general, you should avoid moving the view. The view is your main reference to layout your subviews. Now, the reason why your view goes back to its initial position is most likely because it's being laid out when your app becomes active after going to the background. Note that the view's subviews are not getting re-laid out in this case. – rs7 Aug 18 '20 at 07:47
  • @rs7 What you said makes sense and I found a workaround, hinted by your suggestion, using a dummyView to achieve what I want instead of inset. Thanks:) But it is still unsolved - why only with navigation controller? The moved view stays where it was when app becomes active with UIViewController. – Matthew So Aug 18 '20 at 14:11
  • You are welcome! That's interesting... I'm not sure. – rs7 Aug 19 '20 at 18:23

0 Answers0