Skip to content

Instantly share code, notes, and snippets.

@andrew-levy
Last active April 11, 2024 05:06
Show Gist options
  • Save andrew-levy/6bada5b2f39311a87e48978c3c89d6f6 to your computer and use it in GitHub Desktop.
Save andrew-levy/6bada5b2f39311a87e48978c3c89d6f6 to your computer and use it in GitHub Desktop.
import ExpoModulesCore
import UIKit
import SwiftUI
import React
class SwiftuiView: ExpoView {
var name = "" {
didSet {
updateView(withName: name, withOptions: options)
}
}
var options: [String] = [] {
didSet {
updateView(withName: name, withOptions: options)
}
}
let hostingController = UIHostingController(rootView: MySwiftUIView())
required init(appContext: AppContext? = nil) {
super.init(appContext: appContext)
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
addSubview(hostingController.view)
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: self.topAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: self.bottomAnchor),
hostingController.view.leftAnchor.constraint(equalTo: self.leftAnchor),
hostingController.view.rightAnchor.constraint(equalTo: self.rightAnchor)
])
}
// Update the hosting controller's root view with updated prop values
func updateView(withName name: String, withOptions options: [String]) {
hostingController.rootView = MySwiftUIView(name: name, options: options)
}
}
struct MySwiftUIView: View {
var name = ""
var options: [String] = []
@State var isOpen = false
@State var picker = 0
@State var slider = 50.0
@State var isScaled = false
var body: some View {
NavigationView {
if #available(iOS 14.0, *) {
ScrollView {
VStack(spacing: 20) {
Text("SwiftUI + Expo!")
.font(.largeTitle)
.scaleEffect(isScaled ? 1.5 : 1.0)
.foregroundColor(isScaled ? .purple : .black)
Button("Animations work too!") {
withAnimation {
isScaled.toggle()
}
}
NavigationLink("To Details") {
Text("Details")
}
Picker("Picker", selection: $picker, content: {
ForEach(Array(options.enumerated()), id: \.1) { index, option in
Text(option)
.tag(index)
}
}).pickerStyle(.segmented)
if #available(iOS 16.0, *) {
Button("Toggle Sheet") {
isOpen.toggle()
}.sheet(isPresented: $isOpen) {
Text("Sheet content")
.presentationDetents([.medium, .large])
}.padding(.bottom, 100)
}
}
}.navigationTitle(Text("Home"))
}
}
}
}
import ExpoModulesCore
import SwiftUI
public class SwiftuiViewModule: Module {
public func definition() -> ModuleDefinition {
Name("SwiftuiForm")
View(SwiftuiView.self) {
Prop("name") { (view, name: String) in
view.name = name
}
Prop("options") { (view, options: [String]) in
view.options = options
}
}
}
}
@nandorojo
Copy link

        vc.view.frame = CGRect(x: 0, y: 0, width: 10, height: 200) // TODO: find a better way to do this

Could this just stretch the bounds of ExpoView, since the Expo view is controlled by the style prop? Maybe like this?

vc.view.translatesAutoresizingMaskIntoConstraints = false
vc.view.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
vc.view.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
vc.view.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
vc.view.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true

@andrew-levy
Copy link
Author

andrew-levy commented Oct 9, 2023

@nandorojo Thanks. I tried doing this, but I get this runtime error. I'm probably missing something small

"Unable to activate constraint with anchors <NSLayoutYAxisAnchor:0x600002d1cac0 \"UIView:0x130c1a0a0.top\"> and <NSLayoutYAxisAnchor:0x600002d1f880 \"SwiftuiForm.SwiftuiView:0x124d6c650.top\"> because they have no common ancestor.  Does the constraint or its anchors reference items in different view hierarchies?  That's illegal."

@nandorojo
Copy link

Hmm I see yeah it probably needs a different approach since it’s a VC (I don’t know much about Swift). I wonder if there’s a way to make it stretch the bounds there

@andrew-levy
Copy link
Author

@nandorojo This actually worked. Just needed to call addSubview(vc.view) before setting the constraints. Thanks again!

@cobernhart
Copy link

Hey does the MySwiftUIView correctly clips to Bounds.
In my case it looks like this.
IMG_8154

thx for more info

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment