Depuis iOS14, SwiftUI ne prend actuellement pas en charge View équivalent à WKWebView. Par conséquent, il est nécessaire d'encapsuler et d'utiliser le WKWebView d'UIKit pour SwiftUI. Cette fois, le but est d'afficher une WebView équipée de fonctions de base (barre d'outils, barre de progression), et je voudrais résumer comment utiliser ʻUIViewRepresentable` qui y apparaît.
Pour utiliser la vue d'UIKit avec SwiftUI, vous devez utiliser ʻUIViewRepresentable. ʻUIViewRepresentable
est un wrapper pour utiliser UIKit View dans SwiftUI.
Décrit chaque fonction définie dans le protocole ʻUIViewRepresentable`.
func makeUIView(context: Self.Context) -> Self.UIViewType
Doit être implémenté. Créez une instance de la vue à afficher. La vue UIKit utilisée dans SwiftUI est renvoyée comme valeur de retour.
func updateUIView(Self.UIViewType, context: Self.Context)
Doit être implémenté. Appelé lorsque l'état de l'application est mis à jour. Si la vue est mise à jour, décrivez-la dans cette fonction.
static func dismantleUIView(_ uiView: Self.UIViewType, coordinator: Self.Coordinator)
Appelé lorsque la vue UIKit spécifiée est supprimée. Si nécessaire, décrivez le processus de nettoyage tel que la suppression de la notification enregistrée dans cette fonction.
func makeCoordinator() -> Self.Coordinator
Implémenter lorsqu'un événement doit être notifié du côté de la vue
En définissant Coordinator
, il devient possible d'effectuer la gestion des événements par des opérations utilisateur telles que Delegate.
Passons maintenant au sujet principal de l'affichage WKWebView.
La première consiste simplement à afficher la WebView dans l'interface utilisateur de Swift.
ʻUIViewType devient ʻassociatedtype
, alors changez-le en type de vue de l'UIKit que vous voulez encapsuler.
Cette fois, j'utiliserai WKWebView.
WebView.swift
struct WebView: UIViewRepresentable {
///Afficher à afficher
private let webView = WKWebView()
///URL à afficher
let url: URL
func makeUIView(context: Context) -> WKWebView {
//La valeur de retour est WKWebView et elle est renvoyée.
webView.load(URLRequest(url: url))
return webView
}
func updateUIView(_ uiView: WKWebView, context: Context) { }
}
Ensuite, nous allons créer une barre d'outils avec trois éléments: back`` forward`` reload
.
Tout d'abord, créez une barre d'outils et placez chaque bouton.
Ensuite, utilisez Property Wrappers
pour permettre à WebView de détecter quand chaque bouton est appuyé sur la barre d'outils.
Si vous appuyez sur le bouton de la barre d'outils dans cet état, l'état de l'application sera mis à jour et ʻupdateUIView (_ uiView:, context:) de ʻUIViewRepresentable
se déclenchera.
De ce qui précède, du côté WebView, décrivez l'action en fonction du bouton dans ʻupdateUIView (_ uiView:, context:) `.
WebView.swift
struct WebView: UIViewRepresentable {
//réduction...
///Actions WebView
enum Action {
case none
case goBack
case goForward
case reload
}
///action
@Binding var action: Action
func updateUIView(_ uiView: WKWebView, context: Context) {
///Appelé chaque fois que la valeur liée est mise à jour
///Lorsque l'action est mise à jour, traiter selon la valeur mise à jour
switch action {
case .goBack:
uiView.goBack()
case .goForward:
uiView.goForward()
case .reload:
uiView.reload()
case .none:
break
}
action = .none
}
}
WebToolBarView.swift
struct WebToolBarView: View {
///action
@Binding var action: WebView.Action
var body: some View {
VStack() {
HStack() {
//Mettre à jour les actions en fonction du bouton sur lequel vous appuyez
Button("Back") { action = .goBack }
Button("Forward") { action = .goForward }
Button("Reload") { action = .reload }
}
}
}
}
RichWebView.swift
struct RichWebView: View {
/// URL
let url: URL
///action
@State private var action: WebView.Action = .none
var body: some View {
VStack() {
WebView(url: url,
action: $action)
WebToolBarView(action: $action)
}
}
}
Il est maintenant possible de traiter lorsque le bouton est appuyé dans WebView. Cependant, les boutons peuvent être tapés dans n'importe quel état, donc si vous ne pouvez pas passer à la page précédente ou suivante, désactivez chaque bouton.
** Définir le coordinateur **
Si vous pouvez ou non passer à la page précédente ou suivante est déterminé lorsque le chargement de la page WebView est terminé.
Pour ce faire, vous devez implémenter WKNavigationDelegate
, mais vous ne pouvez pas l'implémenter directement dans WebView.
Donc, avec ʻUIViewRepresentable, vous devez créer un ** Coordinator
, une instance personnalisée ** pour informer l'interface utilisateur Swift des changements reçus de la ** vue UIKit.
WKNavigationDelegate
est implémenté dans Coordinator
, à travers lequel la gestion des événements du côté de l'interface utilisateur Swift est effectuée.
WebView.swift
struct WebView: UIViewRepresentable {
//réduction...
///Puis-je revenir en arrière
@Binding var canGoBack: Bool
///Voulez-vous poursuivre
@Binding var canGoForward: Bool
func makeCoordinator() -> WebView.Coordinator {
return Coordinator(parent: self)
}
}
extension WebView {
final class Coordinator: NSObject, WKNavigationDelegate {
///Vue parent
let parent: WebView
init(parent: WebView) {
self.parent = parent
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
parent.canGoBack = webView.canGoBack
parent.canGoForward = webView.canGoForward
}
}
}
Après cela, recevez chaque valeur avec WebToolBarView
via RichWebView
, et décrivez le traitement d'inactivité et d'activation de chaque bouton, et vous avez terminé.
WebToolBarView.swift
Button("Back") { action = .goBack }.disabled(!canGoBack)
Button("Forward") { action = .goForward }.disabled(!canGoForward)
Enfin, créons une barre de progression.
Vous devez obtenir la «progression estimée» et «est en cours de chargement» de «WKWebView» pour créer une barre de progression.
Cette fois, nous utiliserons KVO pour chacun.
Vous recevrez une notification de modification de View, utilisez donc le Coordinator
que vous avez utilisé précédemment.
WebView.swift
struct WebView: UIViewRepresentable {
//réduction...
///Progression du chargement
@Binding var estimatedProgress: Double
///Que ce soit le chargement
@Binding var isLoading: Bool
static func dismantleUIView(_ uiView: WKWebView, coordinator: Coordinator) {
//Appelé lorsque WKWebView est supprimé
//Désactiver et supprimer les notifications lorsque l'instance est supprimée
coordinator.observations.forEach({ $0.invalidate() })
coordinator.observations.removeAll()
}
}
extension WebView {
final class Coordinator: NSObject, WKNavigationDelegate {
///Vue parent
let parent: WebView
/// NSKeyValueObservations
var observations: [NSKeyValueObservation] = []
init(parent: WebView) {
self.parent = parent
//Enregistrer les notifications
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
]
}
//réduction...
}
}
```
#### Créer une barre de progression
Vous avez maintenant toutes les pièces dont vous avez besoin pour votre barre de progression.
Tout ce que vous avez à faire est de créer `ProgressBarView.swift`, de recevoir la valeur via` RichWebView` et de l'afficher.
#### **`ProgressBarView.swift`**
```swift
struct ProgressBarView: View {
///Progression du chargement
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 {
//réduction...
///Progression du chargement
@State private var estimatedProgress: Double = 0.0
///Que ce soit le chargement
@State private var isLoading: Bool = false
var body: some View {
VStack() {
if isLoading {
ProgressBarView(estimatedProgress: estimatedProgress)
}
//réduction...
}
}
}
Vous avez maintenant implémenté un ensemble de fonctions. Il y a d'autres points à considérer comme la gestion des erreurs, mais je pense que nous avons pu créer une WebView avec des fonctions approximatives.
Cette fois, je l'ai implémenté dans le but d'afficher une WebView riche, mais pour implémenter WebView avec SwiftUI, il est nécessaire de le créer en utilisant les fonctions de base de ʻUIViewRepresentable`, donc c'est juste pour étudier. pense. Si vous êtes intéressé, essayez-le. La source est résumée dans le github suivant, donc si vous êtes intéressé, je vous serais reconnaissant si vous pouviez le voir. (Le côté github contient du code omis ici, comme l'affichage du titre de la barre de navigation et les restrictions de mise en page.) RichWebViewSample
De plus, si vous avez des suggestions d'amélioration ou des opinions concernant cette implémentation, nous vous serions reconnaissants de bien vouloir commenter. Merci beaucoup.