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.
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.
Kommen wir nun zum Hauptthema der WKWebView-Anzeige.
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) { }
}
Als nächstes erstellen wir eine Symbolleiste mit drei Elementen: back`` forward`` reload.
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)
        }
    }
}
Property Wrapper wie @ State und @ Binding werden hier nicht erläutert, da sie vom Hauptthema abweichen.
Es gibt viele Artikel, die ausführlich erklärt werden. Bitte beziehen Sie sich bei Bedarf separat darauf.
State and Data Flow | Apple Developer DocumentationJetzt 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)
Zuletzt erstellen wir einen Fortschrittsbalken.
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.
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.
Recommended Posts