如何在 SwiftUI 中为 WKWebView 创建浏览器选项卡
Posted
技术标签:
【中文标题】如何在 SwiftUI 中为 WKWebView 创建浏览器选项卡【英文标题】:How to create a browser tab for WKWebView in SwiftUI 【发布时间】:2021-03-28 18:57:54 【问题描述】:我正在尝试构建一个新的选项卡功能,但我不太确定如何实现这一点。我在设置新的或以前的 WKWebView 时遇到问题。如果 url 无效,我如何显示 errorView?
这是我目前所拥有的。
编辑:我不太确定如何初始化或如何创建无效 URL 视图。这有点像我的想法
class NavigationState : NSObject, ObservableObject
@Published var url : URL?
let webView = WKWebView()
extension NavigationState : WKNavigationDelegate
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!)
self.url = webView.url
struct WebView : UIViewRepresentable
let request: URLRequest
var navigationState : NavigationState
func makeUIView(context: Context) -> WKWebView
let webView = navigationState.webView
webView.navigationDelegate = navigationState
webView.load(request)
return webView
func updateUIView(_ uiView: WKWebView, context: Context)
struct ContentView: View
@StateObject var navigationState = NavigationState()
@State var tablist = [NavigationState]
@State var validurl = true;
init()
//does not work currently
navigationState.createNewWebView(withRequest: URLRequest(url: URL(string: "https://www.google.com")!))
var body: some View
VStack()
Button("create new tab")
tablist.append(navigationState)
//create and set new webview
Text(navigationState.url?.absoluteString ?? "(none)")
if(validUrl)
WebView(request: URLRequest(url: URL(string: "https://www.google.com")!), navigationState: navigationState)
elseInvalidURL()
HStack
Button("Back")
navigationState.webView.goBack()
Button("Forward")
navigationState.webView.goForward()
TextField()onCommit:
navigationState.selectedWebView?.load(URLRequest(url: URL(string: urlInput)!))
List
ForEach(tabs, id: \.self) tab in
Button(action:
//set to current webview
, label:
Text(tab.webView.url)
)
.onDelete(perform: delete)
编辑初始化
我在 NavigationState 下添加了这段代码,但一直出现空白屏幕。
override init()
super.init()
let wv = WKWebView()
wv.navigationDelegate = self
self.webViews.append(wv)
self.selectedWebView = wv
wv.load(URLRequest(url: URL(string: "https://www.google.com")!))
【问题讨论】:
【参考方案1】:下面是一个比较简单的实现(先代码,后解释):
class NavigationState : NSObject, ObservableObject
@Published var currentURL : URL?
@Published var webViews : [WKWebView] = []
@Published var selectedWebView : WKWebView?
@discardableResult func createNewWebView(withRequest request: URLRequest) -> WKWebView
let wv = WKWebView()
wv.navigationDelegate = self
webViews.append(wv)
selectedWebView = wv
wv.load(request)
return wv
extension NavigationState : WKNavigationDelegate
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!)
if webView == selectedWebView
self.currentURL = webView.url
struct WebView : UIViewRepresentable
@ObservedObject var navigationState : NavigationState
func makeUIView(context: Context) -> UIView
return UIView()
func updateUIView(_ uiView: UIView, context: Context)
guard let webView = navigationState.selectedWebView else
return
if webView != uiView.subviews.first
uiView.subviews.forEach $0.removeFromSuperview()
webView.frame = CGRect(origin: .zero, size: uiView.bounds.size)
uiView.addSubview(webView)
struct ContentView: View
@StateObject var navigationState = NavigationState()
var body: some View
VStack()
Button("create new tab")
navigationState.createNewWebView(withRequest: URLRequest(url: URL(string: "https://www.google.com")!))
Text(navigationState.currentURL?.absoluteString ?? "(none)")
WebView(navigationState: navigationState)
.clipped()
HStack
Button("Back")
navigationState.selectedWebView?.goBack()
Button("Forward")
navigationState.selectedWebView?.goForward()
List
ForEach(navigationState.webViews, id: \.self) tab in
Button(action:
navigationState.selectedWebView = tab
)
Text(tab.url?.absoluteString ?? "?")
我没有尝试存储 NavigationState
s 的数组,而是重构了 NavigationState
以保存 Web 视图的数组。当前 URL 和选定的 Web 视图是 @Published 值,以便父视图可以看到 URL、选定的视图等。
WebView
必须进行重大更改,因为它必须在任何给定时间更新正在显示的 WKWebView
。
这是非常粗略的边缘代码。如果这是我自己的项目,我会做更多的重构,但这应该能让你开始。
关于显示无效 URL 的错误,这实际上是第二个问题,可能需要更清楚(什么构成无效 URL?它来自哪里?你的意思是如果用户输入一个(在 UI 的某些部分你不是在描述)或者如果他们点击了页面上的无效链接?)
【讨论】:
哇,谢谢大家的帮助!我真的是 SwiftUI 的新手,我从你那里学到了很多东西 :) 嗨,詹姆斯——很高兴为您提供帮助。请在有机会时将答案标记为正确,并且(如果没有)继续,如果有帮助,请给它一个支持 完成!同样对于无效的 url 是在提交时加载 url 的文本输入。我想知道如何检查 url 是否有效,并决定是否应该显示我的 invalidURLView 或我的 WKWebView。还有没有办法在初始化时创建一个选项卡?URL(string:)
返回一个可选项(现在,您必须使用!
强制解包)。在您的用户输入中,如果它返回 nil
,您可能会出现错误。关于选项卡,现在有一个空的 WebView 数组。如果您为 NavigationState
创建一个 init
方法,您可以为您的第一个选项卡预先填充一个初始值(确保也加载请求)。
将您的override init()
调用中的所有内容包装在super.init()
下方的DispatchQueue.main.async
块中。我不确定为什么在这种情况下它需要它,但它确实有效。以上是关于如何在 SwiftUI 中为 WKWebView 创建浏览器选项卡的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SwiftUI 中观察 WKWebView 的加载进度?
SwiftUI 中的 WKWebView - 用户与网站交互时如何切换视图?
如何在 SwiftUI 中创建一个列表视图,每个列表项都是一个 WKWebView(我的实现非常慢并且有问题)
如何阻止 SwiftUI 重新加载我通过 UIViewRepresentable 使用的 WKWebView 页面?