Search code examples
iosswiftuiuikitautorotateuihostingcontroller

UIHostingController not resizing on autororation under certain conditions


I see UIHostingController hosting a SwiftUI view which is presented modally. The problem I see is it doesn't resize on autorotation if the modalPresentationStyle is set to overCurrentContext.

  let promptHostingController = UIHostingController(rootView: promptView)
  promptHostingController.isModalInPresentation = true
  promptHostingController.overrideUserInterfaceStyle = .dark
  promptHostingController.modalPresentationStyle = .overCurrentContext
  self.present(promptHostingController, animated: animated)

Setting it to any other value such as overFullScreen solves the problem. Buy wanted to know why it fails to resize with overCurrentContext?


Solution

  • Nothing in the documentation of overCurrentContext says that the presented view would resize to fit the whole screen. It doesn't mention anything about the size of the presented view at all:

    A presentation style where the content is displayed over another view controller’s content.

    The documentation also says:

    So if the presented view controller does not fill the screen with opaque content, the underlying content shows through.

    This is exactly the case here - you did not write code that resizes the view when the screen is rotated, so the view "does not fill the screen" (let alone "opaque content") after the device is rotated.

    The documentation of overFullScreen, however, does say it will "cover" the whole screen.

    A view presentation style in which the presented view covers the screen.

    Note the different choice of words here - "cover" as opposed to just "over".


    Anyway, if you want it to cover the view controller that definesPresentationContext, you can add auto layout constraints to the view yourself.

    // here I'm assuming "view" is the view you want to cover
    let host = UIHostingController(rootView: ...)
    host.modalPresentationStyle = .overCurrentContext
    host.sizingOptions = [.intrinsicContentSize]
    host.presentationController?.delegate = self
    host.view.translatesAutoresizingMaskIntoConstraints = false
    present(host, animated: true) { [self] in
        NSLayoutConstraint.activate([
            host.view.leftAnchor.constraint(equalTo: view.leftAnchor),
            host.view.rightAnchor.constraint(equalTo: view.rightAnchor),
            host.view.topAnchor.constraint(equalTo: view.topAnchor),
            host.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        ])
    }
    

    You should add the constraints after the hosting controller is presented, which is why I put NSLayoutConstraint.activate in the completion handler of present. Before that, the presented view is not yet in the view hierarchy yet.

    Also, use intrinsicContentSize as the sizing option. As its documentation says, you should use this when you layout the hosting view with AutoLayout.