Как открыть и настроить новое окно в SwiftUI?
Я хочу создать веб-браузер, который, если ссылка откроется в новом окне, откроет новое окно (вкладку) с новой ссылкой.
struct WebBrowserApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
@StateObject private var webBrowserModel = WebBrowserModel()
var body: some View {
WebBrowser(webView: webBrowserModel.webView)
.frame(minWidth: 600, maxWidth: .infinity, minHeight: 800, maxHeight: .infinity)
.onAppear() {
webBrowserModel.webView.load(URLRequest(url: URL(string: "https://www.w3schools.com/jsref/met_win_prompt.asp")!))
}
}
}
struct WebBrowser: NSViewRepresentable {
typealias NSViewType = WKWebView
private let webView: WKWebView
init(webView: WKWebView) {
self.webView = webView
}
func makeNSView(context: Context) -> WKWebView {
return self.webView
}
func updateNSView(_ webView: WKWebView, context: Context) {}
}
class WebBrowserModel: NSObject, ObservableObject, WKUIDelegate {
lazy public var webView: WKWebView = {
let configuration = WKWebViewConfiguration()
let webView = WKWebView(frame: CGRect.zero, configuration: configuration)
webView.uiDelegate = self
return webView
}()
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
// Open new window-tab
guard let originWindow = NSApp.keyWindow, let originWindowController = originWindow.windowController else {
return nil
}
originWindowController.newWindowForTab(nil)
guard let newWindow = NSApp.keyWindow, originWindow != newWindow else {
return nil
}
originWindow.addTabbedWindow(newWindow, ordered: .above)
// How to load the new link: navigationAction.request?
return nil
}
}
- Он будет принимать содержимое внутри
WindowGroup
в качестве шаблона для создания нового окна. - У меня есть новый URL в
navigationAction.request
. - Итак, как я могу открыть новую ссылку в webView нового окна?
(Редактировать V2) Вдохновленный комментариями @Asperi, я создал следующий образец. Я сделал статическую переменную доступной из любого места.
struct WebBrowserAppConfig {
static var startURL: URL? = nil
}
Я сделал помощник для создания новой вкладки окна.
extension NSApplication {
static func addTabbedWindowFromKeyWindow(ordered: NSWindow.OrderingMode) {
guard let originWindow = NSApp.keyWindow, let originWindowController = originWindow.windowController else {
return
}
originWindowController.newWindowForTab(nil)
guard let newWindow = NSApp.keyWindow, originWindow != newWindow else {
return
}
originWindow.addTabbedWindow(newWindow, ordered: ordered)
}
}
Затем я устанавливаю конфигурацию в веб-делегате.
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
WebBrowserAppConfig.startURL = navigationAction.request.url
NSApplication.addTabbedWindowFromKeyWindow(ordered: .above)
return nil
}
Затем я получаю доступ к нему в представлении SwiftUI.
struct ContentView: View {
@StateObject private var webBrowserModel = WebBrowserModel()
var body: some View {
WebBrowser(webView: webBrowserModel.webView)
.frame(minWidth: 600, maxWidth: .infinity, minHeight: 800, maxHeight: .infinity)
.onAppear() {
if let url = WebBrowserAppConfig.startURL {
webBrowserModel.webView.load(URLRequest(url: url))
} else {
webBrowserModel.webView.load(URLRequest(url: URL(string: "https://www.w3schools.com/jsref/met_win_prompt.asp")!))
}
}
}
}
Это работает, хотя кажется очень хакерским.