Search code examples
iosswiftautolayoutmacos-big-surmac-catalyst

Mac Catalyst Scene Status and Layout


I have a MacOS(Big Sur) app based on an existing iOS app. The Catalyst app has 4 or 5 scenes(ViewControllers) open and tiled on the screen simultaneously. The user will bounce between scenes, interacting with the app to create some composite data. All the scene are open and visible (no overlap generally, but they can be moved around as desired).

In transitioning to the Catalyst environment with a single code base, I have needed to optimize the views to optimize the big screen, multi window environment. I do this by programmatically enabling/disabling or setting values on layout constraints in the viewWillAppear method of each view controllers in conditional compile blocks under #if targetEnvironment. Everything looks great when all the window scenes first open.

Here is the problem: When leaving focus to another scene, then returning to the original scene, the conditional layout is replaced by stock iOS layout. On regaining focus, the original scene does not call the viewController's

viewWillAppear or viewDidAppear once the scene is visible, it is always Foreground/Active even if it is not topmost with focus. It stays foreground/Active until actually closed. therefore

in Scene Delegate, sceneWillEnterForeground and sceneDidBecomeActive are never called after initially opening scene.

I have tried using the window event to detect change in focus:

nc.addObserver(forName: .init("NSWindowDidBecomeMainNotification"), object: nil, queue: nil) { notification in
    print("This window became focused:", notification.object!)
    self.turnoffConstraintForTextSideStack()
}

This event posts on any of the open scenes changing focus, and my routine executes, changing the layout to Catalyst mode, then, in a few milliseconds, it changes itself back to the iOS configuration, so so redraw/relayout is occurring after my desired layout.

Can I stop the reversion to iOS layout? or failing that, How can I promote/push my layout to be final, after viewWillAppear?


Solution

  • The NSWindowDidBecomeMainNotification event works, it is just non-specific and posts if any of the App views become the focus.

    The issue of Mac Catalyst layouts reverting to iOS layout when a viewController became topmost was resolved by overriding viewDidLayoutSubviews and modifying the appropriate constraints there.