Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I display different content on different screens in iOS 13?

I have an app that will need to connect to an external display, and I want to display different content on both screens (not just mirror the iPad screen).

I have tried adding a Scene Configuration in my Info.plist:

<key>UIApplicationSceneManifest</key>
<dict>
    <key>UIApplicationSupportsMultipleScenes</key>
    <true/>
    <key>UISceneConfigurations</key>
    <dict>
        <key>UIWindowSceneSessionRoleApplication</key>
        <array>
            <dict>
                <key>UISceneConfigurationName</key>
                <string>Default Configuration</string>
                <key>UISceneDelegateClassName</key>
                <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
                <key>UISceneStoryboardFile</key>
                <string>Main</string>
            </dict>
            <dict>
                <key>UISceneConfigurationName</key>
                <string>External Screen</string>
                <key>UISceneDelegateClassName</key>
                <string>$(PRODUCT_MODULE_NAME).ExtSceneDelegate</string>
                <key>UISceneStoryboardFile</key>
                <string>Ext</string>
            </dict>
        </array>
    </dict>
</dict>

I also added a switch to return the correct UISceneConfiguration for each screen.

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    switch connectingSceneSession.role.rawValue {
    case "UIWindowSceneSessionRoleApplication":
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    case "UIWindowSceneSessionRoleExternalDisplay":
        return UISceneConfiguration(name: "External Screen", sessionRole: connectingSceneSession.role)
    default:
        fatalError("No such role, I think? \(connectingSceneSession.role.rawValue)")
    }
}

While the breakpoint I have set in the above code in configurationForConnecting in my AppDelegate is called when I connect the external screen, my app still simply mirrors the iPad screen.

I tried following this tutorial, but since iOS 13 the screen setter is deprecated, and this code does not work.

I really don't know how I can display different content on different physical screens, could someone point me in the right direction?

like image 372
vrwim Avatar asked Mar 03 '23 07:03

vrwim


2 Answers

The answer by rmaddy was partially correct, the configurationForConnecting code was unnecessary. But there was a mistake in my Info.plist. The mistake was that I assigned both configurations to the UIWindowSceneSessionRoleApplication role. It should have been like this:

<key>UIApplicationSceneManifest</key>
<dict>
    <key>UIApplicationSupportsMultipleScenes</key>
    <true/>
    <key>UISceneConfigurations</key>
    <dict>
        <key>UIWindowSceneSessionRoleApplication</key>
        <array>
            <dict>
                <key>UISceneConfigurationName</key>
                <string>Default Configuration</string>
                <key>UISceneDelegateClassName</key>
                <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
                <key>UISceneStoryboardFile</key>
                <string>Main</string>
            </dict>
        </array>
        <key>UIWindowSceneSessionRoleExternalDisplay</key>
        <array>
            <dict>
                <key>UISceneConfigurationName</key>
                <string>External Screen</string>
                <key>UISceneDelegateClassName</key>
                <string>$(PRODUCT_MODULE_NAME).ExtSceneDelegate</string>
                <key>UISceneStoryboardFile</key>
                <string>Ext</string>
            </dict>
        </array>
    </dict>
</dict>

Where the external screen configuration sits under the UIWindowSceneSessionRoleExternalDisplay key.

This works like a charm. I did have to add this code to the willConnectTo in my ExtSceneDelegate to make it fill the screen:

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    windowScene.screen.overscanCompensation = .none
}
like image 119
vrwim Avatar answered May 16 '23 07:05

vrwim


If you are going to setup the scene configurations in Info.plist, don't implement the configurationForConnecting UIApplicationDelegate method. So start by commenting out that method.

Given your Info.plist setup for the scene configuration, a window scene will automatically be created for the external screen. An instance of your ExtSceneDelegate class will be created for you, and it will be connected with your "Ext" storyboard.

Check the console for any errors. If there is any problem with your scene configuration or the external storyboard, you will only see a mirror of your main storyboard and not the external storyboard.

Also make sure your implementation of willConnectTo in your ExtSceneDelegate isn't doing anything to prevent the proper scene setup. The default implementation that does nothing is all you need to have your external storyboard connected to the automatically created window on the external screen.

like image 45
rmaddy Avatar answered May 16 '23 07:05

rmaddy