Poniższe przykłady przedstawiają podzbiór dostępnych opcji. Te przykłady należy traktować jako minimalne, ale wystarczające rozwiązania w danych okolicznościach.
WKWebView użycie w tych przykładach jest ograniczone do obsługi procesu Google Pay i nie obejmuje żadnych dodatkowych funkcji opartych na WebView.
Wdrażając w projekcie dowolne z tych rozwiązań, kieruj się własnym osądem i dostosuj je do konkretnych potrzeb projektu.
Wyświetlanie wyskakującego okienka w kontrolerze tego samego widoku
Ten przykład w języku Swift pokazuje, jak nowy komponent WebView (wyskakujący) może być wyświetlany w tym samym UIViewController, który obejmuje nadrzędny komponent WebView. Aby utworzyć i wyświetlić wyskakujące okienko, zaimplementuj tę metodę z protokołu WKUIDelegate:
/// Creates a new WebView for displaying a popup func webView( _ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { // If the target of the navigation is a new window (popup), this property is nil guard navigationAction.targetFrame == nil else { return nil } // Creates a new WebView for a popup, and displays it in the same view controller (on the top of `mainWebView`) let popupWebView = WKWebView(frame: .zero, configuration: configuration) addWebView(popupWebView) return popupWebView }
Kolejna metoda z tego delegata, która usuwa wyskakujące okienko z ekranu:
/// Removes the WebView from the view hierarchy and updates the UI as needed (after popup was closed) func webViewDidClose(_ webView: WKWebView) { /// Keeping the `mainWebView` on screen, and removing only popups guard webView != mainWebView else { return } webView.removeFromSuperview() }
Funkcja addWebView(_ webView: WKWebView) ustawia też wartość uiDelegate dla przekazanego parametru webView. Oto przykładowa implementacja:
/// Adds a WebView into the view hierarchy /// Same method is being used for displaying both `mainWebView` and any popups func addWebView(_ webView: WKWebView) { webView.uiDelegate = self webView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(webView) NSLayoutConstraint.activate([ webView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), webView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), webView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) ]) }
W przypadku implementacji z jednym kontrolerem widoku należy dodać przycisk „Zamknij”, aby umożliwić użytkownikom zamykanie wyskakujących okienek (np. strony „Warunki usługi”). Ten przycisk może być umieszczony w różnych miejscach w zależności od interfejsu aplikacji. W tym przykładzie przycisk jest dodawany bezpośrednio do widoku WebView:
/// Adds a "Close" button overlay to the top-trailing corner of a given WebView func addCloseButton(to webView: WKWebView) { let buttonSize = 24.0 let buttonMargin = 6.0 let closeAction = UIAction { [weak self] _ in self?.webViewDidClose(webView) } let closeButton = UIButton(type: .system, primaryAction: closeAction) closeButton.translatesAutoresizingMaskIntoConstraints = false var config = UIButton.Configuration.filled() config.baseBackgroundColor = .systemFill.withAlphaComponent(0.5) config.baseForegroundColor = .systemBackground config.buttonSize = .medium config.cornerStyle = .capsule config.image = UIImage(systemName: "xmark", withConfiguration: UIImage.SymbolConfiguration(pointSize: buttonSize / 2, weight: .bold)) closeButton.configuration = config webView.addSubview(closeButton) NSLayoutConstraint.activate([ closeButton.topAnchor.constraint(equalTo: webView.safeAreaLayoutGuide.topAnchor, constant: buttonMargin), closeButton.trailingAnchor.constraint(equalTo: webView.safeAreaLayoutGuide.trailingAnchor, constant: -buttonMargin), closeButton.widthAnchor.constraint(equalToConstant: buttonSize), closeButton.heightAnchor.constraint(equalToConstant: buttonSize) ]) }
Wyświetlanie wyskakującego okienka w nowym kontrolerze widoku
Ten przykład w języku Objective-C pokazuje, jak można wyświetlić nowy komponent WebView (wyskakujący) w nowym kontrolerze widoku (którego można użyć, jeśli aplikacja obsługuje karty).
Jedną z opcji jest to, że kontroler widoku może mieć inicjator, który akceptuje zewnętrzną instancję WKWebView:
/// Creates a view controller with a given WebView - (instancetype)initWithWebView:(WKWebView *)webView { if (self = [super init]) { self.webView = webView; } return self; }
Aby utworzyć i wyświetlić wyskakujące okienko, zaimplementuj tę metodę z protokołu WKUIDelegate:
/// Creates a new WebView for displaying a popup - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures { // If the target of the navigation is a new window (popup), this property is nil if (navigationAction.targetFrame != nil) { return nil; } // Create a new WebView for a popup WKWebView *popupWebView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]; // Create a new instance of `NewViewController` with a newly created WebView, and present it modally NewViewController *popupViewController = [[NewViewController alloc] initWithWebView:popupWebView]; [self presentViewController:popupViewController animated:YES completion:nil]; return popupWebView; }
Kolejna metoda z tego delegata, która usuwa wyskakujące okienko z ekranu:
/// Dismisses the current view controller (after popup was closed) - (void)webViewDidClose:(WKWebView *)webView { [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; }
Wyświetlanie wyskakującego okienka za pomocą SwiftUI
Ten przykład w SwiftUI pokazuje, jak nowy komponent WebView (wyskakujący) może być wyświetlany w tym samym widoku Swift, który obejmuje nadrzędny komponent WebView. Ponieważ WKWebView jest komponentem UIKit, opakuj go w UIViewRepresentable:
/// A SwiftUI wrapper for `WKWebView` struct WebView: UIViewRepresentable { /// Underlying WebView let wkWebView = WKWebView() /// Loads a given `url` into the underlying WebView func load(url: URL) -> Self { wkWebView.load(URLRequest(url: url)) return self } /// Creates the view object representing `WKWebView` and configures its initial state func makeUIView(context: Context) -> some UIView { wkWebView.uiDelegate = context.coordinator return wkWebView } /// When the state of the app changes, SwiftUI calls this method for any changes affecting /// the corresponding UIKit viewAs an alternative, this method could be used to load the `url` /// into the WebView instead of calling `load(url:)` explicitly func updateUIView(_ uiView: UIViewType, context: Context) { } /// Creates a bridge between SwiftUI and `WKUIDelegate` func makeCoordinator() -> WKUIDelegate { /// A coordinator capable of handling `WKUIDelegate` events final class Coordinator: NSObject, WKUIDelegate { /// Main WebView which displays the `url` passed into `SwiftUISurface` let mainWebView: WebView /// Creates a coordinator with a given main WebView init(_ mainWebView: WebView) { self.mainWebView = mainWebView } /// Creates a new WebView for displaying a popup func webView( _ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { // If the target of the navigation is a new window (popup), this property is nil guard navigationAction.targetFrame == nil else { return nil } // Creates a new WebView for a popup which would use the same coordinator let popupWebView = WKWebView(frame: webView.frame, configuration: configuration) popupWebView.translatesAutoresizingMaskIntoConstraints = false popupWebView.uiDelegate = webView.uiDelegate /// Displays the newly created popup WebView on the top of a parent WebView (`mainWebView`) webView.addSubview(popupWebView) NSLayoutConstraint.activate([ popupWebView.leadingAnchor.constraint(equalTo: webView.leadingAnchor), popupWebView.topAnchor.constraint(equalTo: webView.topAnchor), popupWebView.trailingAnchor.constraint(equalTo: webView.trailingAnchor), popupWebView.bottomAnchor.constraint(equalTo: webView.bottomAnchor), ]) return popupWebView } /// Removes the WebView from the view hierarchy and updates the UI as needed (after popup was closed) func webViewDidClose(_ webView: WKWebView) { /// Keeping the `mainWebView` on screen, and removing only popups guard webView != mainWebView.wkWebView else { return } webView.removeFromSuperview() } } return Coordinator(self) } }
Fragment kodu zawiera zarówno UIViewRepresentable otokę dla elementu WebView, jak i niestandardową klasę Coordinator, która może obsługiwać zdarzenia delegowane elementu WebView.
Gdy pojawi się żądanie wyskakującego okienka, tworzy je i umieszcza na wierzchu nadrzędnego widoku WebView. W przypadku zdarzenia zamknięcia wyskakującego okienka – usuwa je z hierarchii widoków.