addSubview SwiftUI View to UIKit UIView in Swift
Asked Answered
B

1

47

I have tried to addSubview a SwiftUI View to UIView. self.view.addSubview(contentView)

Error: Cannot convert value of type 'ContentView' to expected argument type 'UIView'

Kindly help me to implement this UI.

import UIKit
import SwiftUI

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        view.backgroundColor = UIColor.lightGray
        
        let contentView = ContentView()
        view.addSubview(contentView) // Error: Cannot convert value of type 'ContentView' to expected argument type 'UIView'
    }


}


struct ContentView: View {
    var body: some  View {
        Text("Hello world")
    }
    
}
Boohoo answered 17/6, 2019 at 13:1 Comment(3)
View protocol != a UIViewNest
Watch the very first part of Session 231: Integrating SwiftUI. You need to use UIHostingController. developer.apple.com/videos/play/wwdc2019/231Misapprehend
Sorry for the second comment. Since UIHostingController is a UIViewController` and you wish to use addSubview, you'll also need to learn how to use a child view controller (done in UIKit) and part of that involves adding the view as a subview to your parent view. The hosting controllers (one for UIKit, AppKit, and WatchKit) are full controllers, and are easily used for a full screen SwiftUI view. Hope this helps.Misapprehend
G
59

Step 1: Create instances of UIHostingController by using SwiftUI View

struct ContentView : View {
    var body: some View {
        VStack {
            Text("Test")
            Text("Test2")

        }
    }
}

var child = UIHostingController(rootView: ContentView())

Step 2: Add instance of UIHostingController as a child view controller to Any UIKit ViewController

var parent = UIViewController()
child.view.translatesAutoresizingMaskIntoConstraints = false
child.view.frame = parent.view.bounds
// First, add the view of the child to the view of the parent
parent.view.addSubview(child.view)
// Then, add the child to the parent
parent.addChild(child)

You can use the following code to remove a child controller Remove from view Controller

// Then, remove the child from its parent
child.removeFromParent()

// Finally, remove the child’s view from the parent’s
child.view.removeFromSuperview()
Grave answered 27/6, 2019 at 10:5 Comment(5)
Thanks for your answer, so now I can use SwiftUI in Mac statusbar app. But, you are setting the SwiftUI view's frame by the parent view. I want to do it vice versa, is there a way? And that child's frame will always be zeros unless it has not been set, as far I get.Scant
This answer is good, thank you. I know Apple is very big on "just rewrite your app from scratch" and "don't connect with any third-party code". But for people on Earth, it would have been nice if Apple just handled all the boilerplate code above invisibly. Then we can gradually switch out UIViews to Views.Geriatrician
The above doesn't demonstrate what happens when you want to use a SwiftUI View from a UIView directly (i.e. a UIView deep down in the hierarchy wishes to use an existing SwiftUI view, and it doesn't have access to its UIViewController)Guttle
@Guttle That isn't supported by SwiftUI. You should consider refactoring your code so your view's have access to their controllers.Photometer
@Grave I am trying to understand why would you need the UIViewController? UIHostingController(rootView: ContentView()).view you can "basically" convert the swiftUI view to UIView, everything seems to work, can you provide reason, why its "not supported"?Implement

© 2022 - 2024 — McMap. All rights reserved.