Skip to content

UIKIt中如何引入SwiftUI的页面或组件

UIKit跳转到SwiftUI

swift
public struct DemoSwiftUIController: View {
    public var body: some View {
        Text("this is a swiftui controller!")
    }
    public init() {}
}


// UIKit页面
 @IBAction func pushSwiftUIController(_ sender: Any) {
        let swiftUIViewController = UIHostingController(rootView: DemoSwiftUIController())
        self.navigationController?.pushViewController(swiftUIViewController, animated: true)
    }
public struct DemoSwiftUIController: View {
    public var body: some View {
        Text("this is a swiftui controller!")
    }
    public init() {}
}


// UIKit页面
 @IBAction func pushSwiftUIController(_ sender: Any) {
        let swiftUIViewController = UIHostingController(rootView: DemoSwiftUIController())
        self.navigationController?.pushViewController(swiftUIViewController, animated: true)
    }

加载SwiftUI

通过添加UIHostingController.view来实现

swift
    @IBAction func addSwiftUIView(_ sender: Any) {
        let hostingController = UIHostingController(rootView: SwiftUIViewComponent())
        addChildViewController(hostingController)
        self.view.addSubview(hostingController.view)
        // 用于在将`子视图控制器`添加到 `父视图控制器(self)` 或从 `父视图控制器中移除(nil)` 时进行状态更新的方法
        // 如果不调用子视图控制器就无法检测到它是否移动到了父视图控制器(无法知道生命周期)
        hostingController.didMove(toParent: self)
        hostingController.view.backgroundColor = UIColor.red
        hostingController.view.frame = CGRect(x: 100, y: 200, width: 300, height: 80)
    }
    @IBAction func addSwiftUIView(_ sender: Any) {
        let hostingController = UIHostingController(rootView: SwiftUIViewComponent())
        addChildViewController(hostingController)
        self.view.addSubview(hostingController.view)
        // 用于在将`子视图控制器`添加到 `父视图控制器(self)` 或从 `父视图控制器中移除(nil)` 时进行状态更新的方法
        // 如果不调用子视图控制器就无法检测到它是否移动到了父视图控制器(无法知道生命周期)
        hostingController.didMove(toParent: self)
        hostingController.view.backgroundColor = UIColor.red
        hostingController.view.frame = CGRect(x: 100, y: 200, width: 300, height: 80)
    }

可进行简单封装:

swift
import SwiftUI
public protocol SwiftSupportController {}
public extension SwiftSupportController where Self: UIViewController {
    /// 增加swiftUIView
    /// - Parameter content: swiftUI view
    /// - Returns: View
    func addSwiftUIView<Content>(content: Content) -> UIView where Content: View {
        let hostingController = self.swiftUIController(content: content)
        self.view.addSubview(hostingController.view)
        addChildViewController(hostingController)
        hostingController.didMove(toParentViewController: self)
        return hostingController.view
    }

    /// 获取swiftui的 UIHostingController
    /// - Parameter content: swiftUI view
    /// - Returns: View
    func swiftUIController<Content>(content: Content) -> UIViewController where Content: View {
        return UIHostingController(rootView: content)
    }
}
import SwiftUI
public protocol SwiftSupportController {}
public extension SwiftSupportController where Self: UIViewController {
    /// 增加swiftUIView
    /// - Parameter content: swiftUI view
    /// - Returns: View
    func addSwiftUIView<Content>(content: Content) -> UIView where Content: View {
        let hostingController = self.swiftUIController(content: content)
        self.view.addSubview(hostingController.view)
        addChildViewController(hostingController)
        hostingController.didMove(toParentViewController: self)
        return hostingController.view
    }

    /// 获取swiftui的 UIHostingController
    /// - Parameter content: swiftUI view
    /// - Returns: View
    func swiftUIController<Content>(content: Content) -> UIViewController where Content: View {
        return UIHostingController(rootView: content)
    }
}

SwiftUI中使用UIKit

可以参考: [通过抽离SwiftUI代码的方式提高预览速度]

UIKit 和SwiftUI传值交互示例

SwiftUI:

swift
import SwiftUI

public class DemoTitleModel: ObservableObject {
    @Published public var text: String
    public init(text: String) {
        self.text = text
    }
}

public struct DemoChangeTitle: View {
    @ObservedObject var model: DemoTitleModel
    public var body: some View {
        Text(model.text)
    }

    public init(model: DemoTitleModel) {
        self.model = model
    }
}

#Preview {
    let model = DemoTitleModel(text: "default text")
    return DemoChangeTitle(model: model)
}
import SwiftUI

public class DemoTitleModel: ObservableObject {
    @Published public var text: String
    public init(text: String) {
        self.text = text
    }
}

public struct DemoChangeTitle: View {
    @ObservedObject var model: DemoTitleModel
    public var body: some View {
        Text(model.text)
    }

    public init(model: DemoTitleModel) {
        self.model = model
    }
}

#Preview {
    let model = DemoTitleModel(text: "default text")
    return DemoChangeTitle(model: model)
}

UIKit:

swift
import SwiftUI
import UIKit

/// swiftui和uikit交互
class InteractSwiftUIViewController: UIViewController, SwiftSupportController {
    @ObservedObject var viewModel = DemoTitleModel(text: "my default text")
    override func viewDidLoad() {
        super.viewDidLoad()
        let view = addSwiftUIView(content: DemoChangeTitle(model: viewModel))
        view.frame = CGRect(x: 100, y: 100, width: 200, height: 100)
        view.backgroundColor = UIColor.lightGray
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        viewModel.text = "\(viewModel.text) + 1"
    }
}
import SwiftUI
import UIKit

/// swiftui和uikit交互
class InteractSwiftUIViewController: UIViewController, SwiftSupportController {
    @ObservedObject var viewModel = DemoTitleModel(text: "my default text")
    override func viewDidLoad() {
        super.viewDidLoad()
        let view = addSwiftUIView(content: DemoChangeTitle(model: viewModel))
        view.frame = CGRect(x: 100, y: 100, width: 200, height: 100)
        view.backgroundColor = UIColor.lightGray
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        viewModel.text = "\(viewModel.text) + 1"
    }
}