-
-
Save zhelezkov/4eae21af38d07774e102fcaaf314abe5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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