Raisen
Raisen

Reputation: 4495

How to invoke a method on a NSViewRepresentable from a View?

I'm having a hard time to understand how NSViewRepresentable interacts with a SwiftUI view.

For example, in the example below, how can I load a different URL when the button in the view is clicked?

import Cocoa
import SwiftUI
import WebKit
import PlaygroundSupport

struct InternalBrowser: NSViewRepresentable {
    func makeNSView(context: Context) -> WKWebView {
        let browser = WKWebView()
        browser.load(URLRequest(url: URL(string: "https://www.google.com")!))
        return browser
    }
    func updateNSView(_ nsView: WKWebView, context: Context) {
    }
}

struct Browser: View {
    var body: some View {
        GeometryReader { g in
            VStack {
                InternalBrowser().frame(width: 400, height: 400)
                Button(action: {
                    // how to tell InternalBrowser to load an URL here?
                }) {
                    Text("Load Different URL")
                }
            }
        }
    }
}

PlaygroundPage.current.setLiveView(Browser().frame(width: 500, height: 500))

Upvotes: 4

Views: 3017

Answers (1)

Asperi
Asperi

Reputation: 257493

how can I load a different URL when the button in the view is clicked?

Here is a demo of possible approach. Tested with Xcode 11.4 / iOS 13.4

struct InternalBrowser: NSViewRepresentable {
    @Binding var url: URL?

    func makeNSView(context: Context) -> WKWebView {
        return WKWebView()
    }

    func updateNSView(_ browser: WKWebView, context: Context) {
        if let url = self.url, url != browser.url {
            browser.load(URLRequest(url: url))
        }
    }
}

struct Browser: View {
    @State var resourceURL = URL(string: "https://www.google.com")
    var body: some View {
        VStack {
            Button(action: {
                self.resourceURL = URL(string: "https://www.stackoverflow.com")
            }) {
                Text("Load Different URL")
            }
            Divider()
            InternalBrowser(url: self.$resourceURL).frame(width: 400, height: 400)
        }
    }
}

Upvotes: 7

Related Questions