Search code examples
iosxcodemac-catalyst

Mac Catalyst popover set/limit size problem


Is it possible to limit/fix (min/max) popover size on Mac Catalyst? See the attached video.

Example video


Solution

  • Yes, but it's a bit of a hack. Big Sur is loading these presented view controllers as their own windows, so we can grab the window's windowScene and set its sizeRestrictions. The best (?) place to do this is in the presented view controller's viewWillLayoutSubviews method:

    class MyPresentedViewController: UIViewController {
        
        override func viewWillLayoutSubviews() {
            super.viewWillLayoutSubviews()
            
            if #available(macCatalyst 14, *) {
                view.window?.windowScene?.sizeRestrictions?.minimumSize = CGSize(width: 500, height: 500)
                view.window?.windowScene?.sizeRestrictions?.maximumSize = CGSize(width: 800, height: 800)
            }
        }
    }
    

    If you don’t want the presented view to be resizable at all, just set the minimumSize and maximumSize to the same value.

    I don't love using viewWillLayoutSubviews like this, but the windowScene is still nil in viewDidLoad and viewWillAppear, and while it is non-nil in viewDidAppear, setting sizeRestrictions there will cause a visible resize on screen.

    The good news is that this problem may be fixed in Big Sur 11.1. According to the beta release notes, macOS 11.1 will respect preferredContentSize and they won't be resizable by default:

    When you present a view controller with page sheet or form sheet presentation style, the size of the view controller’s root view is, by default, determined by the value returned from the presented view controller’s preferredContentSize method and the view is not resizable. You can arrange for the presented view controller to be resizable by using Auto Layout to specify the maximum and minimum sizes of its root view. To enable this, set the canResizeToFitContent property of the application’s main window to YES. One way to do this is to override the willMove(toWindow:) or didMoveToWindow() methods of a view in the main view controller. (65254666)