1

I'm building a web browser using SwiftUI and I broke the view into 3 parts: SearchView, WebView (UIViewRepresentable).

In SearchView I have @Binding var query which gets updated on onCommit method of TextField. WebView has @Binding var query and @Binding var loadingProgress. Right know webView updates when both query and progress get updated. How I can filter those events and do not reload webView for progress changes?

I suppose I need to work in updateUIView(_ uiView: WKWebView, context: Context) method but I have no idea how to implement this logic. Or maybe all the concept is wrong?

Here is my WebView

struct BrowserWebView: UIViewRepresentable {
    
var webView = WKWebView()

@Binding var query: String
@Binding var loadingProgress: Float

func makeUIView(context: Context) -> WKWebView {
    context.coordinator.addProgressObserver()
    webView.navigationDelegate = context.coordinator
    return webView
}

func updateUIView(_ uiView: WKWebView, context: Context) {
    loadQuery()
}

private func loadQuery() {
    guard let url = URL(string: query) else { return }
    let request = URLRequest(url: url)
    webView.load(request)
}

func makeCoordinator() -> Coordinator {
    return Coordinator(self)
}

class Coordinator: NSObject, WKNavigationDelegate {
    var parent: BrowserWebView
    
    init(_ parent: BrowserWebView) {
        self.parent = parent
    }
    
    func addProgressObserver() {
        parent.webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil)
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if let o = object as? WKWebView, o == parent.webView {
            if keyPath == #keyPath(WKWebView.estimatedProgress) {
                parent.loadingProgress = Float(parent.webView.estimatedProgress)
            }
        }
    }
  }
}

Outside I have @State property which updates ProgressView

Nikolai Prokofev
  • 184
  • 3
  • 14

1 Answers1

0

You can simple compare the webview's current url string with query to skip reloading e.g.:

func updateUIView(_ uiView: WKWebView, context: Context) {
    guard let url = URL(string: query) else { return }
    if uiView.url == nil || uiView.url?.absoluteString.trimmingCharacters(in: CharacterSet(arrayLiteral: "/")) != query {
        let request = URLRequest(url: url)
        uiView.load(request)
    }
}
iUrii
  • 11,742
  • 1
  • 33
  • 48