You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中UIViewRepresentable包装WKWebView隐藏默认加载文本

问题

通过UIViewRepresentable实现SViewerWebView组件,用于加载携带Authorization请求头的网页,通过@Binding的isLoading状态控制自定义ProgressView显示。但加载过程中,自定义加载视图消失后、网页内容显示前,WKWebView会显示默认的"Loading..."文本,如何隐藏该默认文本?

原组件代码:

struct SViewerWebView: UIViewRepresentable{
    var url: String
    var token: String
    @Binding var isLoading: Bool
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    func makeUIView(context: Context) -> WKWebView {
        let webConfiguration = WKWebViewConfiguration()
        let webView = WKWebView(frame:.zero,configuration:webConfiguration)
        webView.allowsBackForwardNavigationGestures = true
        webView.isInspectable = true
        webView.navigationDelegate = context.coordinator
        return webView
    }
    func updateUIView(_ uiView: WKWebView, context: Context) {
        guard let urlforRequest = URL(string: url) else {
            print("❌ Invalid URL:", url)
            return
        }
        var request = URLRequest(url: urlforRequest)
        request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
        
        print("🔄 Loading URL:", url)
        print("🛠 Headers:", request.allHTTPHeaderFields ?? [:])
        
        uiView.load(request)
    }
    
    //coordinator
    class Coordinator: NSObject, WKNavigationDelegate {
        var parent: SViewerWebView

        init(_ parent: SViewerWebView) {
            self.parent = parent
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            DispatchQueue.main.async {
                self.parent.isLoading = false  // Hide loading when page loads
            }
        }

        func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
            DispatchQueue.main.async {
                self.parent.isLoading = false  // Hide loading on error
            }
        }
    }
}

视图层代码:

var body: some View {
        ZStack{
            SViewerWebView(url: webUrl,token: TokenManager.getToken()!,isLoading: $isLoading)
            if isLoading{
                VStack {
                    ProgressView()
                    .progressViewStyle(CircularProgressViewStyle())
                    .scaleEffect(1.5)
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .background(Color.white)
            }
        }
        .ignoresSafeArea()
    }
解决方案

核心是通过初始加载空白页面避免默认"Loading..."文本,同时延迟或监听加载进度确保自定义加载视图在网页内容完全渲染后再隐藏,消除中间的空白过渡问题。

修改步骤:

  1. 初始加载空白页面:在makeUIView中给WKWebView加载空白HTML,替换默认的加载提示
  2. 优化加载状态时机:延迟隐藏加载视图,或监听加载进度确保内容渲染完成
  3. 避免重复加载:在updateUIView中判断当前URL是否与要加载的一致,防止重复请求

修改后的完整代码:

struct SViewerWebView: UIViewRepresentable{
    var url: String
    var token: String
    @Binding var isLoading: Bool
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    func makeUIView(context: Context) -> WKWebView {
        let webConfiguration = WKWebViewConfiguration()
        let webView = WKWebView(frame:.zero,configuration:webConfiguration)
        webView.allowsBackForwardNavigationGestures = true
        webView.isInspectable = true
        webView.navigationDelegate = context.coordinator
        // 初始加载空白页面,避免默认Loading文本
        webView.loadHTMLString("", baseURL: nil)
        // 监听加载进度,确保内容完全渲染
        webView.addObserver(context.coordinator, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil)
        return webView
    }
    
    func updateUIView(_ uiView: WKWebView, context: Context) {
        guard let urlforRequest = URL(string: url), uiView.url != urlforRequest else {
            print("❌ Invalid URL or same URL:", url)
            return
        }
        var request = URLRequest(url: urlforRequest)
        request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
        
        print("🔄 Loading URL:", url)
        print("🛠 Headers:", request.allHTTPHeaderFields ?? [:])
        
        // 开始加载时显示自定义加载视图
        DispatchQueue.main.async {
            self.isLoading = true
        }
        uiView.load(request)
    }
    
    //coordinator
    class Coordinator: NSObject, WKNavigationDelegate {
        var parent: SViewerWebView

        init(_ parent: SViewerWebView) {
            self.parent = parent
        }
        
        deinit {
            // 移除KVO监听,避免内存泄漏
            if let webView = parent.makeUIView(context: Context()) as? WKWebView {
                webView.removeObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress))
            }
        }
        
        override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
            if keyPath == #keyPath(WKWebView.estimatedProgress), let progress = change?[.newKey] as? Double {
                DispatchQueue.main.async {
                    // 加载进度达到100%时隐藏加载视图
                    if progress >= 1.0 {
                        self.parent.isLoading = false
                    }
                }
            }
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            // 作为 fallback,导航完成后延迟隐藏,确保内容渲染
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                self.parent.isLoading = false
            }
        }

        func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
            DispatchQueue.main.async {
                self.parent.isLoading = false
            }
        }
    }
}

说明:

  • 初始空白页面直接覆盖了WKWebView的默认加载提示,避免加载初期显示"Loading..."
  • KVO监听estimatedProgress可以精准捕捉加载完成的时机,确保网页内容已渲染
  • didFinish回调中延迟0.1秒作为兜底,避免进度监听失效的情况
  • updateUIView中的URL判断防止重复触发加载请求

内容的提问来源于stack exchange,提问作者MiguelG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 14:39:57