【问题标题】:SwiftUI: WebKit toolbar buttons not doing anythingSwiftUI:WebKit 工具栏按钮不做任何事情
【发布时间】:2021-08-03 14:17:45
【问题描述】:

这是一个使用 SwiftUI 和 WebKit 制作的 macOS 网络浏览器应用程序。在我的地址工具栏中,我有快捷按钮,例如刷新、返回、前进和指向 YouTube 的快捷链接按钮。但是点击其中任何一个都没有任何反应。

内容视图

struct ContentView: View {
    @StateObject var webModel = WebStateModel()
    @State var text = ""
    
    var body: some View {
   //toolbar
            HStack{
                //Refresh Button
                 Button(action: {
                    WebView(webModel: webModel).refresh()    
                     })  {
                         Image("arrow.left.circle")
                     }
                 //Go Forward Button
                 Button{
                    WebView(webModel: webModel).goForward()

                 } label: {
                     Image("arrow.right.circle")
                     }              
                 //Youtube button
                 Button{
                    WebView(webModel: webModel).youtube()
                         } label: {
                             Image("house.circle")
                             }
            }
        VStack (spacing: 80) {
            TextField("Enter a URL", text: Binding(
                get: { text },
                set: { text = WebStateModel.stripHttps($0) } ), onCommit: {
                    webModel.updateUrl(text)
                })
            WebView(webModel: webModel) //To display the loaded web page
        }
    }
}

WebView 的视图模型

class WebStateModel: ObservableObject {
    @Published var url: URL? = URL(string: "https://www.google.com")
    
    func updateUrl(_ str: String) {
        if let theUrl = URL(string: "https://" + WebStateModel.stripHttps(str)) {
            url = theUrl
        }
    }
    
    static func stripHttps(_ str: String) -> String {
        var txt = str.trim()
        if txt.starts(with: "https://") {
            txt = String(txt.dropFirst(8))
        }
        return txt
    }  
}

包含工具栏快捷功能的WebView。

struct WebView: NSViewRepresentable {
    @ObservedObject var webModel: WebStateModel

    func makeNSView(context: Context) -> WKWebView {
        let wkWebview = WKWebView()
        if let theUrl = webModel.url {
            let request = URLRequest(url: theUrl, cachePolicy: .returnCacheDataElseLoad)
            wkWebview.load(request)
        }
        return wkWebview
    }

    func updateNSView(_ nsView: WKWebView, context: Context) {
        if let theUrl = webModel.url {
            let request = URLRequest(url: theUrl, cachePolicy: .returnCacheDataElseLoad)
            nsView.load(request)
        }
    }
func refresh() {
    let wkWebview = WKWebView()
    wkWebview.reload()
}


func goBack() {
    let wkWebview = WKWebView()
    guard wkWebview.canGoBack else { return }
    wkWebview.goBack()
}


func goForward() {
    let wkWebview = WKWebView()
    guard wkWebview.canGoForward else { return }
    wkWebview.goBack()
}

func youtube() {
    let wkWebview = WKWebView()
         wkWebview.load(URLRequest(url: (URL(string: "https://www.youtube.com")!)))
}
}

编辑我也试过了

func refresh() {
        WKWebView().reload()
    }

    func goBack() {
        guard WKWebView().canGoBack else { return }
        WKWebView().goBack()
    }


    func goForward() {
        guard WKWebView().canGoForward else { return }
        WKWebView().goForward()
    }

    func youtube() {
        WKWebView().load(URLRequest(url: (URL(string: "https://www.youtube.com")!)))
    }

单击工具栏中的任何按钮时,WebView 中没有任何反应。

【问题讨论】:

  • 您正在创建一个对象,每个函数调用let wkWebview = WKWebView() 这是错误的。
  • @swiftnoob 是否为签名和功能中的应用目标打开了应用沙箱?如果是这样(如果您不确定,沙盒可能已启用),您是否选择了允许传入和传出网络连接的复选框? Mac Xcode 项目默认打开应用程序沙箱并关闭网络连接。关闭网络连接后,点击 YouTube 按钮将不会在网络视图中显示 YouTube 主页。

标签: swift swiftui webkit


【解决方案1】:

如前所述,每次调用函数时都会创建一个新对象。 此外,您不应该尝试“返回”按钮内的视图。 SwiftUI 是 基于不断变化的状态值。

改为这样做:

import SwiftUI
import WebKit

@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

class WebStateModel: ObservableObject {
    @Published var url: URL? = URL(string: "https://www.google.com")
    
    func updateUrl(_ str: String) {
        if let theUrl = URL(string: "https://" + WebStateModel.stripHttps(str)) {
            url = theUrl
        }
    }
    
    static func stripHttps(_ str: String) -> String {
        var txt = str.trim()
        if txt.starts(with: "https://") {
            txt = String(txt.dropFirst(8))
        }
        return txt
    }
}

struct WebView: NSViewRepresentable {
    @ObservedObject var webModel: WebStateModel
    
    let wkWebview = WKWebView()
    
    func makeNSView(context: Context) -> WKWebView {
        if let theUrl = webModel.url {
            let request = URLRequest(url: theUrl, cachePolicy: .returnCacheDataElseLoad)
            wkWebview.load(request)
        }
        return wkWebview
    }
    
    func updateNSView(_ nsView: WKWebView, context: Context) {
        if let theUrl = webModel.url {
            let request = URLRequest(url: theUrl, cachePolicy: .returnCacheDataElseLoad)
            nsView.load(request)
        }
    }
    func refresh() {
        wkWebview.reload()
    }
    
    func goBack() {
        guard wkWebview.canGoBack else { return }
        wkWebview.goBack()
    }
    
    func goForward() {
        guard wkWebview.canGoForward else { return }
        wkWebview.goForward()
    }
    
    func youtube() {
        wkWebview.load(URLRequest(url: (URL(string: "https://www.youtube.com")!)))
    }
}

extension String {
    func trim() -> String {
        return self.trimmingCharacters(in: .whitespacesAndNewlines)
    }
}

struct ContentView: View {
    @StateObject var webModel = WebStateModel()
    @State var text = ""
    
    @State var webView: WebView?
    
    var body: some View {
        VStack {
            //toolbar
            HStack{
                Button(action: { webView?.refresh() }) {
                    Image(systemName: "arrow.clockwise.circle")
                }
                Button(action: { webView?.goBack() }) {
                    Image(systemName: "arrow.left.circle")
                }
                Button(action: { webView?.goForward() }) {
                    Image(systemName: "arrow.right.circle")
                }
                Button(action: { webView?.youtube() }) {
                    Image(systemName: "house.circle")
                }
            }
            
            VStack (spacing: 80) {
                TextField("Enter a URL", text: Binding(
                    get: { text },
                    set: { text = WebStateModel.stripHttps($0) } ), onCommit: {
                        webModel.updateUrl(text)
                    })
                webView
            }
        }
        .onAppear {
            webView = WebView(webModel: webModel)
        }
    }
    
}

【讨论】:

  • 它对你有用吗?当我单击 goBack、goForward 或刷新时没有任何反应。现在单击 youtube 按钮会在控制台中显示“WebPageProxy::didFailLoadForFrame: frameID = 3, domain = NSURLErrorDomain, code = -999”。
  • 是的,它对我来说效果很好。尝试按原样使用代码,不要添加其他内容,不要更改某些功能,只需按原样复制和粘贴即可。你在什么系统上和目标是什么?还要听取@Mark Szymczyk 的建议。
猜你喜欢
  • 2020-07-14
  • 2017-12-31
  • 2014-10-07
  • 1970-01-01
  • 2016-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多