SwiftUIでビューを既存のUIKitアプリケーションと並べて構築することは可能ですか?
Objective-Cで記述された既存のアプリケーションがあります。 Swift 5.への移行を開始しました。既存のUIKit .xibビューと一緒にSwiftUIを使用できるかどうか疑問に思っています。
つまり、同じアプリでSwiftUIを使用して作成したビューと、UIKitを使用して作成した他のビューが必要です。もちろん2つを混ぜないでください。
SomeObjCSwiftProject/
SwiftUIViewController.Swift
SwiftUIView.xib
UIKitViewController.Swift
UIKitView.xib
一緒に働く
edit 05/06/19:@Departamento Bの回答で示唆されているように、UIHostingControllerに関する情報を追加しました。クレジットは彼に行きます!
次のようにSwiftUI
UIKit
をSwiftUI
にラップすることにより、既存のView
環境でUIHostingController
コンポーネントを使用できます。
let swiftUIView = SomeSwiftUIView() // swiftUIView is View
let viewCtrl = UIHostingController(rootView: swiftUIView)
UIHostingController
をオーバーライドして、ニーズに合わせてカスタマイズすることもできます。 g。期待どおりにpreferredStatusBarStyle
経由で機能しない場合は、SwiftUI
を手動で設定します。
UIHostingController
はドキュメント化されています ここ 。
既存のUIKit
ビューをSwiftUI
環境で使用する必要がある場合は、UIViewRepresentable
プロトコルが役立ちます。それは ここ で文書化されており、実際に this 公式Appleチュートリアルで見ることができます。
互換性
UIKit
はiOS 13以降でのみ利用できるため、SwiftUI
コンポーネントとSwiftUI
コンポーネントを組み合わせて使用できるのは、アプリがiOS 13以降をターゲットにしている場合のみです。詳細は this postを参照してください。
現時点ではクラスのドキュメントは書かれていませんが、UIHostingController<Content>
はあなたが探しているもののようです: https://developer.Apple.com/documentation/swiftui/uihostingcontroller
アプリで次のコード行を試してみました。
let vc = UIHostingController(rootView: BenefitsSwiftUIView())
ここで、BenefitsSwiftUIView
は、View
のデフォルトの「Hello World」SwiftUI
です。これは期待どおりに機能します。 UIHostingController
をサブクラス化した場合にも機能します。
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)
}
}
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>
同期を維持する主な項目は次のとおりです。
SceneDelegate
ファイルの場所を認識できるようにしますUISceneConfiguration
をロードできるようにしますこれを行った後、新しく作成したHomeListビュー(SwiftUIオブジェクト)を読み込むことができました
レガシーObjective CプロジェクトからSwiftUI
ビューを作成する場合は、この手法が完璧に機能しました。
Objective-CアプリへのSwiftUIの追加 を参照してください
それを書いた私たちの友人への称賛。
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
併用できます。 UIView
に準拠してView
をUIViewRepresentable
に「転送」できます。詳細は 公式チュートリアル にあります。
ただし、互換性についても考慮する必要があります。
これは、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.
/// ...
}
したがって、下位互換性はありません。