ios - 在 SwiftUI WebView 中拉动刷新

标签 ios swiftui webview wkwebview pull-to-refresh

我正在寻找为 SwiftUI WebView 实现“拉动刷新”机制的最佳方法。

这是我能写的最接近的解决方案,但是刷新过程并未结束(事件指示器存在并且没有其他事情发生) 我从这篇文章中获取的这两个扩展 https://stackoverflow.com/a/36256504

import SwiftUI
import WebKit

struct WebView: UIViewRepresentable {
    let webView: WKWebView

    init() {
        webView = WKWebView(frame: .zero)
        webView.load(URLRequest(url: URL(string: "https://cnn.com")!))
        webView.setPullToRefresh(type: .embed)
    }

    func makeUIView(context: Context) -> WKWebView {
        webView
    }
    func updateUIView(_ uiView: WKWebView, context: Context) {}
}

extension WKWebView {
    var refreshControl: UIRefreshControl? { (scrollView.getAllSubviews() as [UIRefreshControl]).first }

    enum PullToRefreshType {
        case none
        case embed
    }

    func setPullToRefresh(type: PullToRefreshType) {
        (scrollView.getAllSubviews() as [UIRefreshControl]).forEach { $0.removeFromSuperview() }
        switch type {
            case .none: break
            case .embed: _setPullToRefresh(target: self, selector: #selector(webViewPullToRefreshHandler(source:)))
        }
    }

    private func _setPullToRefresh(target: Any, selector: Selector) {
        let refreshControl = UIRefreshControl()
        refreshControl.addTarget(target, action: selector, for: .valueChanged)
        scrollView.addSubview(refreshControl)
    }

    @objc func webViewPullToRefreshHandler(source: UIRefreshControl) {
        guard let url = self.url else { source.endRefreshing(); return }
        load(URLRequest(url: url))
    }
}

extension UIView {

    class func getAllSubviews<T: UIView>(from parenView: UIView) -> [T] {
        return parenView.subviews.flatMap { subView -> [T] in
            var result = getAllSubviews(from: subView) as [T]
            if let view = subView as? T { result.append(view) }
            return result
        }
    }

    func getAllSubviews<T: UIView>() -> [T] { return UIView.getAllSubviews(from: self) as [T] }
}

最佳答案

好的,这是我解决这个问题的方法。 在 iPhone 14 Pro、iOS 15 和 16

上检查

swift 5

import SwiftUI
import WebKit

struct HomeView: UIViewRepresentable {

    var webView = WebView()

    func makeUIView(context: Context) -> WKWebView {
        webView.webView
    }
    func updateUIView(_ uiView: WKWebView, context: Context) {}
}

class WebView: NSObject {
    var webView: WKWebView!

    override init() {
        super.init()
        webView = WKWebView(frame: .zero)
        webView.load(URLRequest(url: URL(string: "https://cnn.com")!))
        webView.setPullToRefresh()
        webView.navigationDelegate = self
    }
}

extension WebView: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        webView.refreshControl?.endRefreshing()
    }

    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        webView.refreshControl?.endRefreshing()
    }

    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        webView.refreshControl?.endRefreshing()
    }
}

extension WKWebView {
    var refreshControl: UIRefreshControl? {
        (scrollView.getAllSubviews() as [UIRefreshControl]).first
    }

    func setPullToRefresh() {
        (scrollView.getAllSubviews() as [UIRefreshControl]).forEach {
            $0.removeFromSuperview()
        }

        let refreshControl = UIRefreshControl()
        refreshControl.addTarget(self, action: #selector(webViewPullToRefreshHandler(source:)), for: .valueChanged)
        scrollView.addSubview(refreshControl)
    }

    @objc func webViewPullToRefreshHandler(source: UIRefreshControl) {
        guard let url = self.url else {
            source.endRefreshing()
            return
        }
        load(URLRequest(url: url))
    }
}

extension UIView {
    class func getAllSubviews<T: UIView>(from parentView: UIView) -> [T] {
        return parentView.subviews.flatMap { subView -> [T] in
            var result = getAllSubviews(from: subView) as [T]
            if let view = subView as? T {
                result.append(view)
            }
            return result
        }
    }

    func getAllSubviews<T: UIView>() -> [T] {
        return UIView.getAllSubviews(from: self) as [T]
    }
}

关于ios - 在 SwiftUI WebView 中拉动刷新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74295405/

相关文章:

android - HTTPS 证书有时会在 Android WebView 中失败

iOS App 在 segue 崩溃(断点出现在 func prepareForSegue 处)

ios - AVAudioEngine 麦克风启动时崩溃

swiftui - 为什么在 swiftUI 中弹出全屏?

ios - 如何在 SwiftUI 中获取 View 或屏幕的高度和宽度

ios - SwiftUI - 如何将 EnvironmentObject 传递给 View 模型?

ios - React Native - NavigatorIOS

ios - UIView 动画立即发生

android - NameNotFoundException WebView

javascript - 将 javascript 注入(inject) Android webview 不显示