Include SwiftUI views in existing UIKit applicatio

2020-02-03 04:54发布

Is is possible to build views with SwiftUI side by side with an existing UIKit application?

I have an existing application written in Objective-C. I've begun migrating to Swift 5. I'm wondering if I can use SwiftUI alongside my existing UIKit .xib views.

That is to say I want some views built with SwiftUI and some other views built with UIKit in the same app. Not mixing the two of course.

SomeObjCSwiftProject/
    SwiftUIViewController.swift
    SwiftUIView.xib
    UIKitViewController.swift
    UIKitView.xib

Working alongside each other

标签: swift swiftui
8条回答
别忘想泡老子
2楼-- · 2020-02-03 05:28

Others has been showcasing how to use UIHostingController.

I can show how you can present a UIViewController from SwiftUI UIViewControllerRepresentable:

struct YourViewControllerWrapper: UIViewControllerRepresentable {
    typealias UIViewControllerType = YourViewController

    func makeUIViewController(context: UIViewControllerRepresentableContext<YourViewControllerWrapper>) -> YourViewController {
        let storyBoard = UIStoryboard(name: "YourStoryboard", bundle: Bundle.main)
        return storyBoard.instantiateViewController(withIdentifier: "YourViewController") as! YourViewController
    }

    func updateUIViewController(_ uiViewController: YourViewController, context: UIViewControllerRepresentableContext<YourViewController>) {
        // do nothing
    }
}
查看更多
混吃等死
3楼-- · 2020-02-03 05:35
import Foundation
    #if canImport(SwiftUI)
    import SwiftUI

internal final class SomeRouter {
    fileprivate weak var presentingViewController: UIViewController!

    function navigateToSwiftUIView() {
       if #available(iOS 13, *) {
            let hostingController = UIHostingController(rootView: contentView())  
presentingViewController?.navigationController?.pushViewController(hostingController, animated: true)
            return
        }
        //Keep the old way when not 13.
}
#endif
查看更多
来,给爷笑一个
4楼-- · 2020-02-03 05:35

If you're looking to create a SwiftIU view from a legacy Objective C project, then this technique worked perfectly for me,

See Adding SwiftUI to Objective-C Apps

Kudos to our friend who wrote that up.

查看更多
\"骚年 ilove
5楼-- · 2020-02-03 05:41

One item I have not seen mentioned yet, and involves Xcode 11 beta 5 (11M382q) involves updating your app's info.plist file.

For my scenario, I am taking an existing Swift & UIKit based application and fully migrating it to be an iOS 13 & pure SwiftUI app, so backwards compatibility is not a concern for me.

After making the necessary changes to AppDelegate:

// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication,
                 configurationForConnecting connectingSceneSession: UISceneSession,
                 options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    return UISceneConfiguration(name: "Default Configuration",
                                sessionRole: connectingSceneSession.role)
}

And adding in a SceneDelegate class:

import UIKit
import SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: HomeList())
            self.window = window
            window.makeKeyAndVisible()
        }
    }
}

I was encountering a problem where my SceneDelegate was not being called. This was fixed by adding the following into my info.plist file:

<key>UIApplicationSceneManifest</key>
<dict>
    <key>UIApplicationSupportsMultipleScenes</key>
    <false/>
    <key>UISceneConfigurations</key>
    <dict>
        <key>UIWindowSceneSessionRoleApplication</key>
        <array>
            <dict>
                <key>UISceneClassName</key>
                <string></string>
                <key>UISceneDelegateClassName</key>
                <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
                <key>UISceneConfigurationName</key>
                <string>Default Configuration</string>
                <key>UISceneStoryboardFile</key>
                <string>LaunchScreen</string>
            </dict>
        </array>
    </dict>
</dict>

And a screenshot to see: enter image description here

The main items to keep in sync are:

  • Delegate Class Name so that Xcode knows where to find your SceneDelegate file
  • Configuration Name so that the call in AppDelegate can load the correct UISceneConfiguration

After doing this, I was then able to load my newly created HomeList view (A SwiftUI object)

查看更多
我想做一个坏孩纸
6楼-- · 2020-02-03 05:45

UIHostingController

Although at the moment the documentation for the class has not been written, UIHostingController<Content> seems to be what you're looking for: https://developer.apple.com/documentation/swiftui/uihostingcontroller

I've just tried it in my app with the following line of code:

let vc = UIHostingController(rootView: BenefitsSwiftUIView())

Where BenefitsSwiftUIView is just the default "Hello World" View from SwiftUI. This works exactly as you expect it. It also works if you subclass UIHostingController.

查看更多
The star\"
7楼-- · 2020-02-03 05:47

edit 05/06/19: Added information about UIHostingController as suggested by @Departamento B in his answer. Credits go to him!


Using SwiftUI with UIKit

One can use SwiftUI components in existing UIKit environments by wrapping a SwiftUI View into a UIHostingController like this:

let swiftUIView = SomeSwiftUIView() // swiftUIView is View
let viewCtrl = UIHostingController(rootView: swiftUIView)

It's also possible to override UIHostingController and customize it to one's needs, e. g. by setting the preferredStatusBarStyle manually if it doesn't work via SwiftUI as expected.

UIHostingController is documented here.


Using UIKit with SwiftUI

If an existing UIKit view should be used in a SwiftUI environment, the UIViewRepresentable protocol is there to help! It is documented here and can be seen in action in this official Apple tutorial.


Compatibility

Please note that UIKit and SwiftUI components can only be used in conjunction if the app targets iOS 13+, as SwiftUI is only available iOS 13+. See this post for more information.

查看更多
登录 后发表回答