如何在SwiftUI中为WKWebView创建浏览器选项卡
我试图建立一个新的标签功能,但我不太确定如何才能做到这一点。设置新的或以前的WKWebView时遇到问题。如果url无效,如何显示errorView 这就是我目前所拥有的 编辑:我不太确定如何初始化或如何创建invalidurl视图。这有点像我脑子里在想什么如何在SwiftUI中为WKWebView创建浏览器选项卡,swiftui,Swiftui,我试图建立一个新的标签功能,但我不太确定如何才能做到这一点。设置新的或以前的WKWebView时遇到问题。如果url无效,如何显示errorView 这就是我目前所拥有的 编辑:我不太确定如何初始化或如何创建invalidurl视图。这有点像我脑子里在想什么 class NavigationState : NSObject, ObservableObject { @Published var url : URL? let webView = WKWebView() } exte
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)
} else{InvalidURL()}
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")!))
}
下面是一个相对简单的实现(先编写代码,然后解释): 我没有尝试存储
NavigationState
s数组,而是重构NavigationState
来保存一个web视图数组。当前URL和所选web视图是@Published值,以便父视图可以看到URL、所选视图等
WebView
必须进行重大更改,因为它必须更新在任何给定时间显示的WKWebView
这是相当粗糙的边缘代码。如果这是我自己的项目,我会做更多的重构,但这应该会让你开始
关于使用无效URL显示错误,这实际上是第二个问题,可能需要更清楚地说明(无效URL的组成部分是什么?它来自何处?你的意思是用户只需输入一个(在你没有描述的UI的某个部分),还是他们单击页面上的无效链接?哇,谢谢你的帮助!我对SwiftUI真的很陌生,我从你身上学到了很多:)嗨,詹姆斯,很高兴能帮上忙。当你有机会的时候,请把答案标记为正确的,如果你没有机会的话,请继续进行,如果答案有帮助的话,请投上一票!对于无效url,还有一个在提交时加载url的textinput。我想知道如何检查url是否有效,以及是否应该显示invalidURLView或WKWebView。还有一种方法可以在初始化时创建选项卡吗?
URL(字符串:)
返回一个可选选项(现在,您正在使用!
强制展开它)。在用户输入中,如果返回nil
,则可能会出现错误。关于选项卡,现在有一个空的WebView数组。如果为NavigationState
创建一个init
方法,则可以为第一个选项卡预先填充一个初始值(确保也加载请求)。将override init()
调用中的所有内容包装在super.init()
下面的DispatchQueue.main.async{}
块中。我不确定为什么在这种情况下它需要这样,但它是有效的。
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 ?? "?")
}
}
}
}
}
}