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