skip to Main Content

I am using SwiftUI, so I have a wrapper around the Webview, like this:

import SwiftUI
import WebKit


struct WebView: UIViewRepresentable {
    var url: String
    let webView = WKWebView()
    
    func makeUIView(context: Context) -> WKWebView  {
        webView.evaluateJavaScript("navigator.userAgent") { (result, error) in
            print(result as! String)
        }
        return webView
    }
    
    func updateUIView(_ uiView: WKWebView, context: Context) {
        let request = URLRequest(url: URL(string:url)!)
        uiView.load(request)
    }
}

How can I execute a function/method whenever the user makes scroll to the website?

2

Answers


  1. To get scroll position updates you need to create coordinator and override makeCoordinator() method and return instance of your coordinator. In makeUIView(_:) method just assign scrollview delegate to context.coordinator (context object in provided in arguments of makeUIView method)

    Pass binding from view to coordinator and coordinator is responsible to update that binding. Here is code for that

    struct WebView: UIViewRepresentable {
        
        var url: String
        @Binding var contentOffset: CGPoint
        
        init(url: String, contentOffset: Binding<CGPoint>) {
            self.url = url
            _contentOffset = contentOffset
        }
        
        let webView = WKWebView()
        
        func makeUIView(context: Context) -> WKWebView  {
            webView.scrollView.delegate = context.coordinator // assign delegation
            
            webView.evaluateJavaScript("navigator.userAgent") { (result, error) in
                print(result as! String)
            }
            return webView
        }
        
        func updateUIView(_ uiView: WKWebView, context: Context) {
            let request = URLRequest(url: URL(string:url)!)
            uiView.load(request)
        }
        
        func makeCoordinator() -> Coordinator {
            .init(contentOffset: $contentOffset) // create coordinator for delegation
        }
        
        
        class Coordinator: NSObject, UIScrollViewDelegate {
            
            @Binding var contentOffset: CGPoint
            
            init(contentOffset: Binding<CGPoint>) {
                _contentOffset = contentOffset
            }
            
            func scrollViewDidScroll(_ scrollView: UIScrollView) {
                contentOffset = scrollView.contentOffset
            }
        }
    }
    
    
    Login or Signup to reply.
  2. WebView with UIScrollViewDelegate support.

    import SwiftUI
    import WebKit
    
    struct WebView: UIViewRepresentable {
    
    var url: URL
    var scrollViewDelegate: UIScrollViewDelegate?
    
    func makeUIView(context: Context) -> WKWebView {
        let webView = WKWebView()
        webView.scrollView.delegate = scrollViewDelegate
        return webView
    }
    
    func updateUIView(_ webView: WKWebView, context: Context) {
        let request = URLRequest(url: url)
        webView.load(request)
    }}
    

    Observable ScrollViewDetector

    import UIKit.UIScrollView
    
    final class ScrollViewDetector: NSObject, ObservableObject, UIScrollViewDelegate {
    
    @Published var isScrolledEnd = false
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let contentLoaded = scrollView.contentSize.height > 1000
        let endOfContentReached = scrollView.contentSize.height - scrollView.contentOffset.y - scrollView.frame.size.height < 100
       
        if contentLoaded &&  endOfContentReached {
            isScrolledEnd = true
        }
    }}
    

    Agreement view with sticky footer button.

    import SwiftUI
    
    struct AgreementView: View {
    
    @StateObject var scrollViewDetector = ScrollViewDetector()
    
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                WebView(url: URL(string: "YOUR URL")!, scrollViewDelegate: scrollViewDetector)
                
                // Footer Navigation Link
                NavigationLink {
                    EmptyView()
                } label: {
                    // Your Label
                    Button("Accept")
                        .padding()
                        .background(Color.white.opacity(!scrollViewDetector.isScrolledEnd ? 0.9 : 0.0))
                }
                .position(x: geometry.width(0.5), y: geometry.height(0.9))
                .opacity(!scrollViewDetector.isScrolledEnd ? 0.6 : 1.0)
                .disabled(!scrollViewDetector.isScrolledEnd ? true : false)
            }
        }
    }}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search