Versuchen Sie, mit UIViewRepresentable eine leicht reichhaltige Webansicht in SwiftUI anzuzeigen

Einführung

Ab iOS14 unterstützt SwiftUI derzeit keine Ansicht, die WKWebView entspricht. Daher ist es erforderlich, WIKebView für SwiftUI von UIKit zu verpacken und zu verwenden. Dieses Mal besteht das Ziel darin, eine WebView anzuzeigen, die mit Grundfunktionen (Symbolleiste, Fortschrittsleiste) ausgestattet ist, und ich möchte zusammenfassen, wie die darin angezeigte "UIViewRepresentable" verwendet wird.

Über UIViewRepresentable

Sie müssen "UIViewRepresentable" verwenden, um UIKits Ansicht mit SwiftUI zu verwenden. UIViewRepresentable ist ein Wrapper für die Verwendung von UIKit View in SwiftUI. Beschreibt jede im Protokoll "UIViewRepresentable" definierte Funktion.

func makeUIView(context: Self.Context) -> Self.UIViewType

Muss implementiert werden. Erstellen Sie eine Instanz der anzuzeigenden Ansicht. Die in SwiftUI verwendete UIKit-Ansicht wird als Rückgabewert zurückgegeben.

func updateUIView(Self.UIViewType, context: Self.Context)

Muss implementiert werden. Wird aufgerufen, wenn der Status der App aktualisiert wird. Wenn die Ansicht aktualisiert wird, beschreiben Sie sie in dieser Funktion.

static func dismantleUIView(_ uiView: Self.UIViewType, coordinator: Self.Coordinator)

Wird aufgerufen, wenn die angegebene UIKit-Ansicht gelöscht wird. Beschreiben Sie gegebenenfalls den Bereinigungsprozess, z. B. das Löschen der registrierten Benachrichtigung in dieser Funktion.

func makeCoordinator() -> Self.Coordinator

Implementieren, wenn ein Ereignis von der Ansichtsseite aus benachrichtigt werden soll. Durch die Definition von "Koordinator" kann die Ereignisbehandlung von Benutzeroperationen wie "Delegieren" ausgeführt werden.

Erstellen Sie eine WebView mit WKWebView

Kommen wir nun zum Hauptthema der WKWebView-Anzeige.

WKWebView anzeigen

Die erste besteht darin, das WebView einfach in der Swift-Benutzeroberfläche anzuzeigen. Da "UIViewType" zu "zugeordnetem Typ" wird, ändern Sie ihn in den Ansichtstyp von UIKit, den Sie umbrechen möchten. Dieses Mal werde ich WKWebView verwenden.

WebView.swift


struct WebView: UIViewRepresentable {
    ///Ansicht zum Anzeigen
    private let webView = WKWebView()
    ///URL zum Anzeigen
    let url: URL

    func makeUIView(context: Context) -> WKWebView {
        //Der Rückgabewert ist WKWebView und wird zurückgegeben.
        webView.load(URLRequest(url: url))
        return webView
    }

    func updateUIView(_ uiView: WKWebView, context: Context) { }
}

Erstellen Sie eine Symbolleiste

Als nächstes erstellen wir eine Symbolleiste mit drei Elementen: back`` forward`` reload.

Steuern von Aktionen beim Tippen auf eine Schaltfläche

Erstellen Sie zunächst eine Symbolleiste und platzieren Sie jede Schaltfläche. Verwenden Sie als Nächstes "Property Wrapper", damit WebView erkennt, wann auf jede Schaltfläche in der Symbolleiste getippt wird. Wenn Sie in diesem Status auf die Schaltfläche in der Symbolleiste tippen, wird der Status der App aktualisiert und das "updateUIView (_ uiView :, context :)" von "UIViewRepresentable" wird ausgelöst. Beschreiben Sie auf der WebView-Seite die Aktion anhand der Schaltfläche in "updateUIView (_ uiView :, context :)".

WebView.swift


struct WebView: UIViewRepresentable {
    //Kürzung...

    ///WebView-Aktionen
    enum Action {
        case none
        case goBack
        case goForward
        case reload
    }

    ///Aktion
    @Binding var action: Action

    func updateUIView(_ uiView: WKWebView, context: Context) {
        ///Wird jedes Mal aufgerufen, wenn der gebundene Wert aktualisiert wird
        ///Wenn die Aktion aktualisiert wird, verarbeiten Sie sie gemäß dem aktualisierten Wert
        switch action {
        case .goBack:
            uiView.goBack()
        case .goForward:
            uiView.goForward()
        case .reload:
            uiView.reload()
        case .none:
            break
        }
        action = .none
    }
}

WebToolBarView.swift


struct WebToolBarView: View {
    ///Aktion
    @Binding var action: WebView.Action

    var body: some View {
        VStack() {
            HStack() {
                //Aktualisieren Sie die Aktion gemäß der getippten Schaltfläche
                Button("Back") { action = .goBack }
                Button("Forward") { action = .goForward }
                Button("Reload") { action = .reload }
            }
        }
    }
}

RichWebView.swift


struct RichWebView: View {
    /// URL
    let url: URL
    ///Aktion
    @State private var action: WebView.Action = .none

    var body: some View {
        VStack() {
            WebView(url: url,
                    action: $action)
            WebToolBarView(action: $action)
        }
    }
}

Deaktivierung der Taste

Jetzt ist es möglich zu verarbeiten, wenn die Schaltfläche in WebView getippt wird. Die Schaltflächen können jedoch in jedem Status getippt werden. Wenn Sie also nicht zur vorherigen oder nächsten Seite wechseln können, deaktivieren Sie jede Schaltfläche.

** Koordinator definieren ** Ob Sie zur vorherigen oder nächsten Seite wechseln können, wird festgelegt, wenn das Laden der WebView-Seite abgeschlossen ist. Dazu müssen Sie "WKNavigationDelegate" implementieren, können es jedoch nicht direkt in WebView implementieren. Mit UIViewRepresentable müssen Sie also einen ** Koordinatorerstellen, eine benutzerdefinierte Instanz **, um die von der UIKit-Ansicht empfangenen Änderungen an die Swift-Benutzeroberfläche zu übermitteln. WKNavigationDelegate ist in Coordinator` implementiert, über den die Ereignisbehandlung auf der Swift-UI-Seite durchgeführt wird.

WebView.swift


struct WebView: UIViewRepresentable {
    //Kürzung... 

    ///Kann ich zurück gehen?
    @Binding var canGoBack: Bool
    ///Willst du fortfahren
    @Binding var canGoForward: Bool

    func makeCoordinator() -> WebView.Coordinator {
        return Coordinator(parent: self)
    }
}

extension WebView {
    final class Coordinator: NSObject, WKNavigationDelegate {
        ///Übergeordnete Ansicht
        let parent: WebView

        init(parent: WebView) {
            self.parent = parent
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            parent.canGoBack = webView.canGoBack
            parent.canGoForward = webView.canGoForward
        }
    }
}

Danach erhalten Sie jeden Wert mit "WebToolBarView" über "RichWebView" und beschreiben die Inaktivität und Aktivierungsverarbeitung jeder Schaltfläche, und fertig.

WebToolBarView.swift


    Button("Back") { action = .goBack }.disabled(!canGoBack)
    Button("Forward") { action = .goForward }.disabled(!canGoForward)

Erstellen Sie einen Fortschrittsbalken

Zuletzt erstellen wir einen Fortschrittsbalken.

Holen Sie sich den Wert mit KVO

Sie müssen den "geschätzten Fortschritt" und "isLoading" der "WKWebView" abrufen, um den Fortschrittsbalken zu erstellen. Dieses Mal werden wir jeweils KVO verwenden. Sie erhalten eine Änderungsbenachrichtigung von View. Verwenden Sie daher den zuvor verwendeten "Koordinator".

WebView.swift


struct WebView: UIViewRepresentable {
    //Kürzung... 

     ///Ladevorgang
    @Binding var estimatedProgress: Double
    ///Ob geladen
    @Binding var isLoading: Bool

    static func dismantleUIView(_ uiView: WKWebView, coordinator: Coordinator) {
        //Wird aufgerufen, wenn WKWebView gelöscht wird
        //Deaktivieren und löschen Sie Benachrichtigungen, wenn die Instanz gelöscht wird
        coordinator.observations.forEach({ $0.invalidate() })
        coordinator.observations.removeAll()
    }
}

extension WebView {
    final class Coordinator: NSObject, WKNavigationDelegate {
        ///Übergeordnete Ansicht
        let parent: WebView
        /// NSKeyValueObservations
        var observations: [NSKeyValueObservation] = []

        init(parent: WebView) {
            self.parent = parent
            //Benachrichtigungen registrieren
            let progressObservation = parent.webView.observe(\.estimatedProgress, options: .new, changeHandler: { _, value in
                parent.estimatedProgress = value.newValue ?? 0
            })
            let isLoadingObservation = parent.webView.observe(\.isLoading, options: .new, changeHandler: { _, value in
                parent.isLoading = value.newValue ?? false
            })
            observations = [
                progressObservation,
                isLoadingObservation
            ]
        }
        //Kürzung...
    }
}
```

#### Erstellen Sie einen Fortschrittsbalken
 Sie haben jetzt alle Teile, die Sie für Ihren Fortschrittsbalken benötigen.
 Sie müssen lediglich "ProgressBarView.swift" erstellen, den Wert über "RichWebView" empfangen und anzeigen.


#### **`ProgressBarView.swift`**
```swift

struct ProgressBarView: View {
    ///Ladevorgang
    var estimatedProgress: Double

    var body: some View {
        VStack {
            GeometryReader { geometry in
                Rectangle()
                    .foregroundColor(Color.gray)
                    .opacity(0.3)
                    .frame(width: geometry.size.width)
                Rectangle()
                    .foregroundColor(Color.blue)
                    .frame(width: geometry.size.width * CGFloat(estimatedProgress))
            }
        }.frame(height: 3.0)
    }
}

RichWebView.swift


struct RichWebView: View {
    //Kürzung...

    ///Ladevorgang
    @State private var estimatedProgress: Double = 0.0
    ///Ob geladen
    @State private var isLoading: Bool = false

    var body: some View {
        VStack() {
            if isLoading {
                ProgressBarView(estimatedProgress: estimatedProgress)
            }
            //Kürzung...
        }
    }
}

Sie haben jetzt eine Reihe von Funktionen implementiert. Es gibt noch andere Punkte zu beachten, wie z. B. die Fehlerbehandlung, aber ich denke, wir konnten eine WebView mit groben Funktionen erstellen.

abschließend

Dieses Mal habe ich es implementiert, um ein reichhaltiges WebView anzuzeigen. Um WebView mit SwiftUI zu implementieren, muss es jedoch mit den Grundfunktionen von "UIViewRepresentable" erstellt werden, sodass es genau das Richtige für das Studium ist. Überlegen. Wenn Sie interessiert sind, versuchen Sie es bitte. Die Quelle ist im folgenden Github zusammengefasst. Wenn Sie also interessiert sind, würde ich es begrüßen, wenn Sie es sehen könnten. (Die Github-Seite enthält Code, der hier weggelassen wurde, z. B. die Titelanzeige der Navigationsleiste und Einschränkungen für das Layout.) RichWebViewSample

Wenn Sie Verbesserungsvorschläge oder Meinungen zu dieser Implementierung haben, würden wir uns freuen, wenn Sie dies kommentieren könnten. Vielen Dank.

Verweise

Recommended Posts

Versuchen Sie, mit UIViewRepresentable eine leicht reichhaltige Webansicht in SwiftUI anzuzeigen
Erstellen Sie mit Selenide in 5 Minuten eine automatische Browser-Betriebsumgebung
Versuchen Sie, ein Bulletin Board in Java zu erstellen
So beheben Sie einen Absturz beim Löschen von Realm-Daten in der Liste der schnellen Benutzeroberfläche
Versuchen Sie, die Primzahl mit dem Booleschen Typ anzuzeigen
[Swift] So zeigen Sie die eingegebenen Zeichen im Widget über UserDefaults an, wenn Sie das WidgetKit verwenden
[Swift] Farbe in den Benutzerstandards mit der Swift-Benutzeroberfläche speichern (Hinweis)
So zeigen Sie eine Browser-Vorschau mit VS-Code an
So konvertieren Sie A in a und a in A mit logischem Produkt und Summe in Java
Versuchen Sie, ein eingeschränktes FizzBuzz-Problem in Java zu lösen
Versuchen Sie, mit Docker eine Java-Entwicklungsumgebung zu erstellen
Ich möchte einen relativen Pfad in einer Situation finden, in der Pfad verwendet wird
So zeigen Sie Diagramme in Ruby on Rails an (LazyHighChart)
Zeigen Sie die API-Definition in der Swagger-Benutzeroberfläche mit Docker + Rails6 + apipie an
So ändern Sie die Hintergrundfarbe der Navigationsleiste usw. in der Swift-Benutzeroberfläche
Versuchen Sie es mit RocksDB mit Java
Fotobibliothek mit Swift UI