Passing data from simple NSView to SwiftUI View
Here is a solution (with some replicated parts). Tested with Xcode 11.4 / macOS 10.15.4
class KeyboardInput: ObservableObject {
@Published var keyCode: UInt16 = 0
}
struct KeyboardEvent: NSViewRepresentable {
@Binding var keyStorage: UInt16 // << here !!
init(into storage: Binding<UInt16>) {
_keyStorage = storage
}
class KeyView: NSView {
var owner: KeyboardEvent? // << view holder
override var acceptsFirstResponder: Bool { true }
override func keyDown(with event: NSEvent) {
print("\(event.keyCode)")
owner?.keyStorage = event.keyCode
}
}
func makeNSView(context: Context) -> NSView {
let view = KeyView()
view.owner = self // << inject
DispatchQueue.main.async {
view.window?.makeFirstResponder(view)
}
return view
}
func updateNSView(_ nsView: NSView, context: Context) {
}
}
struct ContentView: View {
@EnvironmentObject var input: KeyboardInput // save the keyCode here
var body: some View {
VStack {
Text("Code: \(input.keyCode)")
KeyboardEvent(into: $input.keyCode) // << binding !!!
}
}
}
Passing an EnvronmentObject to NSHostingControllers
Yes, in such case EnvironmentObject is not injected automatically. The solution would be to separate content into designated views (for better design) and inject environment object manually.
Here it is
Text(self.env.value)
GeometryReader { geometry in
SplitView(master: {
MasterView().environmentObject(self.env)
}, detail: {
HStack {
DetailView().environmentObject(self.env)
}).frame(width: geometry.size.width, height: geometry.size.height)
}
and views
struct MasterView: View {
var body: some View {
Text("master")
.background(Color.yellow)
}
}
struct DetailView: View {
var body: some View {
HStack {
Text(self.env.value) }
.background(Color.orange)
}
}
How to pass one SwiftUI View as a variable to another View struct
To sum up everything I read here and the solution which worked for me:
struct ContainerView<Content: View>: View {
@ViewBuilder var content: Content
var body: some View {
content
}
}
This not only allows you to put simple View
s inside, but also, thanks to @ViewBuilder
, use if-else
and switch-case
blocks:
struct SimpleView: View {
var body: some View {
ContainerView {
Text("SimpleView Text")
}
}
}
struct IfElseView: View {
var flag = true
var body: some View {
ContainerView {
if flag {
Text("True text")
} else {
Text("False text")
}
}
}
}
struct SwitchCaseView: View {
var condition = 1
var body: some View {
ContainerView {
switch condition {
case 1:
Text("One")
case 2:
Text("Two")
default:
Text("Default")
}
}
}
}
Bonus:
If you want a greedy container, which will claim all the possible space (in contrary to the container above which claims only the space needed for its subviews) here it is:
struct GreedyContainerView<Content: View>: View {
@ViewBuilder let content: Content
var body: some View {
content
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
If you need an initializer in your view then you can use @ViewBuilder
for the parameter too. Even for multiple parameters if you will:
init(@ViewBuilder content: () -> Content) {…}
Swifui: MacOS App: Fetching Core Data in ContentView OK, but how to use the result from AppDelegate?
You need to inject Order
to the environment if it will be used as an @EnvironmentObject
:
let order = Order() // declare it once
let contentView = ContentView().environmentObject(order) // inject to the environment
Problem With Bindings with an NSViewRepresentable hosted NSScrollView
It is State
- it is updated when is used in body, so instead use like below:
struct ContentView: View{
@State var offset: CGFloat = 10.0
var body: some View {
VStack {
Text("Offset: \(offset)") // << here !!
MyScrollView(offset: $offset){
ZStack{
Rectangle().foregroundColor(.clear).frame(width: 1200, height: 1000)
Rectangle().foregroundColor(.blue).frame(width: 100, height: 100)
}
}
}
}
}
Related Topics
Swiftui Behavior of .Frame(Height: Nil)
Swift: Search Bar Created at Auto Focus
Why Does Realm Use Realmoptional<Int> Rather Than Int? for Optional Properties
Loading Views into Nscontainerview with Swift
Why There Is a Overflow with Swift Language When Assign a 8 Bits Binary Value to a Var of Int8 Type
Delegate Must Respond to Locationmanager:Didupdatelocations Swift Eroor
How to Remove Space Above and Below Text View in Swiftui
Is There *Any* Situation Under Which "For _ in [1,2,3]" Will Not Loop at All
Is There a Way I Can Combine a Geofirestore Query with a Normal Firestore Query
How to Add Openssl to a Swift Project
Implementing a Hash Combiner in Swift
How to Pass Binding to Child View in the New Navigationstack.Navigationdestination
Code Highlighting in Latex for Swift
Searchbar Problem While Trying to Search Firestore and Reload the Tableview
Swift Error: 'Sequence' Requires the Types 'T' and 'Arrayslice<T>' Be Equivalent