1

I am using my own custom container view controller that is modally presented from a root view controller (so the container is not the root view controller itself). Root view controller gets its layout handled properly when the in-call status bar is shown. Now if I modally present the custom container with its child (lets say instance of SomeViewController), the child is laid out as expected. If an in-call status bar is shown while the custom container is already presented, the child adjusts correctly.

The problem arises when the in-call status bar is shown while the custom container is not yet presented. If I present the custom container while there is an in-call status bar, the bottom of the child view gets cropped by the size of the extended status bar (i.e., 20 points) - it seems like either the size of the frame is not correct, or there is an offset set to it. If I dismiss in-call status bar, the top gets adjusted to the newly gained space, but the bottom stays cropped.

Following shows the relevant code of the container view:

class ContainerController: UIViewController {

    var selectedViewController: UIViewController?

    override func viewDidLoad() {
        super.viewDidLoad()

        if let selectedViewController = selectedViewController {
            initialTransition(to: selectedViewController)
        }
    }

    fileprivate func initialTransition(to viewController: UIViewController) {
        guard self.isViewLoaded else {
            return
        }
        self.addChildViewController(viewController)
        viewController.view.frame = self.view.frame
        self.view.addSubview(viewController.view)
        viewController.didMove(toParentViewController: self)
    }

    // rest of the code omitted
}

The container view is presented using this code in the root view controller:

let container = ContainerController()
trainingContainer.selectedViewController = SomeViewController()
self.present(trainingContainer, animated: true, completion: nil)

While there are several SO questions about similar issues (SO question, another SO question, etc.), most of them suggest either solutions that did not work (e.g., old wantsFullScreenLayout and its successors), or seemed a bit too heavyweight (observing status bar did change to adapt layout), especially considering that when the child view controller was presented directly, it was behaving correctly.

Milan Nosáľ
  • 19,169
  • 4
  • 55
  • 90

1 Answers1

0

After playing around I was able to determine that there was a problem with the frame being set - the frame of the container view controller seemed to be offseted but not resized when the initialTransition(to:) was called (in container's viewDidLoad), thus causing the child the get a frame that overlapped the bottom of the screen by the offset - 20 points.

My first approach was to add setting the frame once again in container's viewDidAppear, which in the end solved the problem, but cause a glitch - for a moment the bottom seemed cropped, and then viewDidAppear was called and the layout was adjusted correctly. This glitch looked bad.

I finally achieved what I wanted by overriding container's viewDidLayoutSubviews and setting the frame of the child there (thus when the container gets notified to adjust its frame to the status bar, the information about a new frame gets passed to the child).

override func viewDidLayoutSubviews() {
    self.selectedViewController?.view.frame = self.view.frame
    super.viewDidLayoutSubviews()
}
Milan Nosáľ
  • 19,169
  • 4
  • 55
  • 90