Skip to content

Instantly share code, notes, and snippets.

@zhelezkov
Forked from andrew-levy/SwiftUIViewModule.swift
Created October 9, 2023 09:02
Show Gist options
  • Save zhelezkov/4eae21af38d07774e102fcaaf314abe5 to your computer and use it in GitHub Desktop.
Save zhelezkov/4eae21af38d07774e102fcaaf314abe5 to your computer and use it in GitHub Desktop.
import ExpoModulesCore
import UIKit
import SwiftUI
// Native view and module definition
public class SwiftuiViewModule: Module {
public func definition() -> ModuleDefinition {
Name("SwiftuiView")
View(SwiftuiView.self) {
// Define your props here
Prop("name") { (view, name: String) in
view.name = name
}
Prop("options") { (view, options: [String]) in
view.options = options
}
}
}
}
// Here you can initialize your ViewController and add it as a subview.
class SwiftuiView: ExpoView {
// When props are updated, update the view controller's view
var name = "" {
didSet {
myViewController?.updateView(withName: name, withOptions: options)
}
}
var options: [String] = [] {
didSet {
myViewController?.updateView(withName: name, withOptions: options)
}
}
private var myViewController: MyViewController?
required init(appContext: AppContext? = nil) {
super.init(appContext: appContext)
// init the view controller
let vc = MyViewController()
vc.view.frame = CGRect(x: 0, y: 0, width: 10, height: 200) // TODO: find a better way to do this
// add it as a subview of the ExpoView
addSubview(vc.view)
myViewController = vc
}
}
// ViewController responsible for embedding your SwiftUI view into the view hierarchy using a UIHostingController
class MyViewController: UIViewController {
// init the hosting controller. set the rootView to your SwiftUI view
let hostingController = UIHostingController(rootView: MySwiftUIView())
override func viewDidLoad() {
super.viewDidLoad()
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(hostingController.view)
// setup constraints
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: self.view.topAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
hostingController.view.leftAnchor.constraint(equalTo: self.view.leftAnchor),
hostingController.view.rightAnchor.constraint(equalTo: self.view.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)
}
}
// Your SwiftUI view
struct MySwiftUIView: View {
var name = ""
var options: [String] = []
@State var isOpen = false
@State var picker = 0
@State var isScaled = false
var body: some View {
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()
}
}
if #available(iOS 14.0, *) {
Label(name, systemImage: name)
.padding()
.foregroundColor(.blue)
}
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)
}
}.background(Color(UIColor.systemGroupedBackground))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment