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

WKWebView加载时Loading动画卡顿问题求助

解决WKWebView加载时动画卡顿的问题

我来帮你分析下问题根源,然后给出具体的修复方案:

问题原因拆解

  1. 线程错误:你在Alamofire的响应闭包中直接调用webView.load(),但Alamofire的响应闭包默认运行在后台队列,在后台线程操作UI组件(WKWebView)会导致主线程阻塞,直接让加载动画卡顿。
  2. 不可靠的结束时机:依赖JS发送loading-finished事件来隐藏动画的方式不够稳定,如果JS事件延迟或失败,动画会一直挂着,也可能间接加重线程冲突。

具体修复步骤

1. 强制UI操作在主线程执行

修改Alamofire的请求逻辑,把webView.load()的调用切换到主线程,同时加上错误处理:

func loadWebview(){
    Loading.shared.show(self.view)
    Alamofire.request(MYAPI, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: nil)
        .responseJSON { response in
            // 切换到主线程处理UI操作
            DispatchQueue.main.async {
                // 处理请求失败的情况
                guard let responseData = response.result.value as? [String: Any], 
                      let key = responseData["key"] as? String else {
                    Loading.shared.hide(animated: true)
                    return
                }
                // 构造URL并加载
                guard let url = URL(string: "https://path-to-load/\(key)") else {
                    Loading.shared.hide(animated: true)
                    return
                }
                self.webView!.load(URLRequest(url: url))
            }
    }
}

2. 用WKNavigationDelegate监听加载状态(替代JS事件)

通过系统代理方法捕获WKWebView的加载完成时机,比JS事件更可靠:
首先在viewDidLoad中设置代理:

override func viewDidLoad() {
    super.viewDidLoad()
    webView = WKWebView(frame: webViewContainer.bounds, configuration: webConfig)
    webView!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    webView?.scrollView.isScrollEnabled = false
    // 添加导航代理设置
    webView?.navigationDelegate = self
    webViewContainer.addSubview(webView!)
    loadWebview()
}

然后实现代理方法:

extension MyViewController: WKNavigationDelegate {
    // 页面加载完成时触发
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        Loading.shared.hide(animated: true)
    }
    
    // 可选:处理加载失败的场景
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        Loading.shared.hide(animated: true)
        // 这里可以添加错误提示逻辑
    }
}

3. 确保Loading类的UI操作全在主线程

修改Loading的show方法,把所有UI相关操作包在主线程里,避免线程冲突:

public func show(_ view: UIView, inView: Bool = false) {
    DispatchQueue.main.async { [weak self] in
        guard let self = self else { return }
        var window: UIView!
        if inView == false, let w = view.window {
            window = w
        } else {
            window = view
        }
        if self.blurredEffectView.superview == window {
            return
        }
        // 先移除旧动画,避免重复添加
        self.imageView.layer.removeAnimation(forKey: "rotationAnimation")
        // 创建旋转动画
        let rotation: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
        rotation.toValue = NSNumber(value: Double.pi * 2)
        rotation.duration = 1
        rotation.isCumulative = true
        rotation.repeatCount = Float.greatestFiniteMagnitude
        self.imageView.layer.add(rotation, forKey: "rotationAnimation")
        
        // 布局动画视图
        self.imageView.center = window.center
        self.blurredEffectView.frame = window.bounds
        window.addSubview(self.blurredEffectView)
        self.blurredEffectView.fadeIn()
    }
}

额外优化建议

  • 给Loading类的hide方法也加上主线程包裹,确保淡出动画流畅执行;
  • 可以给Loading添加一个isShowing状态标记,避免重复调用show方法导致动画叠加。

这样修改后,加载动画会在WKWebView整个加载过程中持续流畅转动,直到页面加载完成(或失败)才会自动隐藏,彻底解决卡顿问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:22:48