在 WebView 中检测滚动和点击会阻止 SwiftUI 中的滚动

Detect Scroll and Tap in WebView blocks the scroll in SwiftUI

我在 SwiftUI 中有一个 WebViewUIViewRepresentable,我想获取触摸和滑动(滚动)的坐标。但问题是,如果我尝试获取坐标,WebView 中的网站将禁用滚动,就像阻止 UIKit Wrapper 的手势一样。这种行为背后发生了什么,解决它的方法是什么?因为否则代码工作完美。

SwiftUI代码:

struct TaskSwipeGesture: View {
    
    let urlWeb: String = "https://www.google.com/?client=safari"
    
    var body: some View {
        WebView(url: urlWeb)
            .gesture(DragGesture(minimumDistance: 0, coordinateSpace: .local)
                        .onChanged({ value in
                print("Change: X Coordinate is: \(value.location.x), Y Coordinate is: \(value.location.y)")
            })
                        .onEnded({ value in
                print("Ended: X Coordinate is: \(value.location.x), Y Coordinate is: \(value.location.y)")
            })
            )
    }
}

WebView 包装器:

struct WebView: UIViewRepresentable {
    let url: String
    
    func makeUIView(context: Context) -> some WKWebView {
        return WKWebView()
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
        let request = URLRequest(url: URL(string: url)!)
        uiView.load(request)
    }
}

您可以使用 webView.scrollView.delegate

以 UIKit 方式处理事件

首先你需要创建ScrollViewDelegate

class MyScrollViewDelegate: NSObject {
    weak var webView: WKWebView?
}

extension MyScrollViewDelegate: UIScrollViewDelegate {
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        printLocation(for: scrollView, label: "will begin dragging")
    }

    func scrollViewWillEndDragging(
        _ scrollView: UIScrollView,
        withVelocity velocity: CGPoint,
        targetContentOffset: UnsafeMutablePointer<CGPoint>)
    {
        printLocation(for: scrollView, label: "will end dragging")
    }

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if scrollView.isTracking {
            printLocation(for: scrollView, label: "is tracking")
        }
    }
    
    private func printLocation(for scrollView: UIScrollView, label: String) {
        if let webView = webView {
            print("\(label) \(scrollView.panGestureRecognizer.location(in: webView))")
        }
    }
}

然后将其应用到您的 WebView 包装器中

struct WebView: UIViewRepresentable {
    let url: String
    let scrollViewDelegate = MyScrollViewDelegate()

    func makeUIView(context: Context) -> some WKWebView {
        let webView = WKWebView()
        scrollViewDelegate.webView = webView
        webView.scrollView.delegate = scrollViewDelegate
        return webView
    }

    func updateUIView(_ uiView: UIViewType, context: Context) {
        let request = URLRequest(url: URL(string: url)!)
        uiView.load(request)
    }
}

之后,ContentView会变成这样

struct TaskSwipeGesture: View {
    let urlWeb: String = "https://www.google.com/?client=safari"
    var body: some View {
        WebView(url: urlWeb)
    }
}