web-dev-qa-db-ja.com

既存のUIKitアプリケーションにSwiftUIビューを含める

SwiftUIでビューを既存のUIKitアプリケーションと並べて構築することは可能ですか?

Objective-Cで記述された既存のアプリケーションがあります。 Swift 5.への移行を開始しました。既存のUIKit .xibビューと一緒にSwiftUIを使用できるかどうか疑問に思っています。

つまり、同じアプリでSwiftUIを使用して作成したビューと、UIKitを使用して作成した他のビューが必要です。もちろん2つを混ぜないでください。

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

一緒に働く

49
visc

edit 05/06/19:@Departamento Bの回答で示唆されているように、UIHostingControllerに関する情報を追加しました。クレジットは彼に行きます!


UIKitでのSwiftUIの使用

次のようにSwiftUIUIKitSwiftUIにラップすることにより、既存のView環境でUIHostingControllerコンポーネントを使用できます。

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

UIHostingControllerをオーバーライドして、ニーズに合わせてカスタマイズすることもできます。 g。期待どおりにpreferredStatusBarStyle経由で機能しない場合は、SwiftUIを手動で設定します。

UIHostingControllerはドキュメント化されています ここ


SwiftUIでのUIKitの使用

既存のUIKitビューをSwiftUI環境で使用する必要がある場合は、UIViewRepresentableプロトコルが役立ちます。それは ここ で文書化されており、実際に this 公式Appleチュートリアルで見ることができます。


互換性

UIKitはiOS 13以降でのみ利用できるため、SwiftUIコンポーネントとSwiftUIコンポーネントを組み合わせて使用​​できるのは、アプリがiOS 13以降をターゲットにしている場合のみです。詳細は this postを参照してください。

49
fredpi

UIHostingController

現時点ではクラスのドキュメントは書かれていませんが、UIHostingController<Content>はあなたが探しているもののようです: https://developer.Apple.com/documentation/swiftui/uihostingcontroller

アプリで次のコード行を試してみました。

let vc = UIHostingController(rootView: BenefitsSwiftUIView())

ここで、BenefitsSwiftUIViewは、Viewのデフォルトの「Hello World」SwiftUIです。これは期待どおりに機能します。 UIHostingControllerをサブクラス化した場合にも機能します。

14
Departamento B

SwiftUIをUIKitビューコントローラーに埋め込む場合は、コンテナービューを使用します。

class ViewController: UIViewController {
    @IBOutlet weak var theContainer: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let childView = UIHostingController(rootView: SwiftUIView())
        addChild(childView)
        childView.view.frame = theContainer.bounds
        theContainer.addSubview(childView.view)
        childView.didMove(toParent: self)
    }
}

参考

10
Mike Lee

Xcode 11ベータ5(11M382q)が関係する、まだ見たことのない項目の1つに、アプリのinfo.plistファイルの更新があります。

私のシナリオでは、既存のSwift&UIKitベースのアプリケーションを使用して、それをiOS 13と純粋なSwiftUIアプリに完全に移行しているため、下位互換性は問題ではありません。

AppDelegateに必要な変更を加えた後:

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

そして、SceneDelegateクラスを追加します。

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()
        }
    }
}

SceneDelegateが呼び出されないという問題が発生しました。これは、以下をinfo.plistファイルに追加することで修正されました。

<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>

そして見るスクリーンショット: enter image description here

同期を維持する主な項目は次のとおりです。

  • デリゲートクラス名は、XcodeがSceneDelegateファイルの場所を認識できるようにします
  • 構成名AppDelegateの呼び出しが正しいUISceneConfigurationをロードできるようにします

これを行った後、新しく作成したHomeListビュー(SwiftUIオブジェクト)を読み込むことができました

6
CodeBender

レガシーObjective CプロジェクトからSwiftUIビューを作成する場合は、この手法が完璧に機能しました。

Objective-CアプリへのSwiftUIの追加 を参照してください

それを書いた私たちの友人への称賛。

2
Snips
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
1
patilh

併用できます。 UIViewに準拠してViewUIViewRepresentableに「転送」できます。詳細は 公式チュートリアル にあります。

ただし、互換性についても考慮する必要があります。

これは、SwiftUIのプロトコルViewのコードスニペットです。

///
/// You create custom views by declaring types that conform to the `View`
/// protocol. Implement the required `body` property to provide the content
/// and behavior for your custom view.
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol View : _View {

    /// The type of view representing the body of this view.
    ///
    /// When you create a custom view, Swift infers this type from your
    /// implementation of the required `body` property.
    /// ...
}

したがって、下位互換性はありません。

  • iOS 13.0以降
  • macOS 10.15以降
  • watchOS 6.0以降
1
Mint