SwiftUI:WKWebView 在 macOS 上截断页面内容(NSViewRepresentable)
Posted
技术标签:
【中文标题】SwiftUI:WKWebView 在 macOS 上截断页面内容(NSViewRepresentable)【英文标题】:SwiftUI: WKWebView Cutting Off Page Content on macOS (NSViewRepresentable) 【发布时间】:2019-12-15 20:50:57 【问题描述】:我有一个基本的 NSViewRepresentable
实现 WKWebView
,用于 macOS 上的 SwiftUI 应用程序。 UIViewRepresentable
等效项在 ios 上运行良好,但在 macOS(本机,不是 Catalyst)上,顶部内容总是被切断。
丢失的量总是等于父视图(例如选项卡视图)及其填充的大小,这表明 Web 视图不断将其内容缩放到 window 大小,而不是 em>查看大小。
例如这个页面:
...应该如下(如Chrome中所示)。整个导航栏已被裁剪(尽管两侧似乎没有受到影响)。
关于如何解决此问题的任何建议?有趣的是,如果我在选项卡之间来回切换,内容会正确显示约 1 秒,然后调整内容大小,使其再次被切断。这让我觉得updateNSView
方法需要一些东西,但我不确定是什么。
似乎与here 讨论的问题类似,但这是针对基于 IB 的应用程序,我看不到将其应用于 SwiftUI 的方法。
使用的代码如下。注意:网页视图作为一个属性保存,因此可以被其他方法引用(例如触发页面加载、刷新、返回等)
public struct WebBrowserView
private let webView: WKWebView = WKWebView()
// ...
public func load(url: URL)
webView.load(URLRequest(url: url))
public class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate
var parent: WebBrowserView
init(parent: WebBrowserView)
self.parent = parent
public func webView(_: WKWebView, didFail: WKNavigation!, withError: Error)
// ...
public func webView(_: WKWebView, didFailProvisionalNavigation: WKNavigation!, withError: Error)
// ...
public func webView(_: WKWebView, didFinish: WKNavigation!)
// ...
public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!)
// ...
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)
decisionHandler(.allow)
public func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView?
if navigationAction.targetFrame == nil
webView.load(navigationAction.request)
return nil
public func makeCoordinator() -> Coordinator
Coordinator(parent: self)
#if os(macOS) // macOS Implementation (iOS version omitted for brevity)
extension WebBrowserView: NSViewRepresentable
public typealias NSViewType = WKWebView
public func makeNSView(context: NSViewRepresentableContext<WebBrowserView>) -> WKWebView
webView.navigationDelegate = context.coordinator
webView.uiDelegate = context.coordinator
return webView
public func updateNSView(_ nsView: WKWebView, context: NSViewRepresentableContext<WebBrowserView>)
#endif
示例用法:
struct BrowserView: View
private let browser = WebBrowserView()
var body: some View
HStack
browser
.onAppear()
self.browser.load(url: URL(string: "https://***.com/tags")!)
.padding()
struct ContentView: View
@State private var selection = 0
var body: some View
TabView(selection: $selection)
Text("Email View")
.tabItem
Text("Email")
.tag(0)
BrowserView()
.tabItem
Text("Browser")
.tag(1)
.padding()
【问题讨论】:
测试您的代码,我得到“'WebBrowserView' 类型的值没有成员'load'。我做错了什么?我将所有这些都粘贴到 ContentView.swift 中? 谢谢@TheNeil!您的建议帮助我获得了我希望运行的浏览器页面,运行。现在我只需要删除“电子邮件/浏览器”拆分,并以某种方式使其显示整个页面而没有任何额外的窗口装饰:) 我非常感谢编辑和建议。我已经在这个问题上摸索了大约一周,试图找到一些“真正有用”的东西,大多数在线教程都是针对 iOS 的 WKWebView。 谢谢! @TheNeil我唯一缺少的基本上是“完整功能”,即当我在浏览器页面上单击“文件浏览器”(上传图像)时,.app 不会向我显示 Finder窗户。如果我能让它运行起来,那就太棒了:) @esaruoho 祝你好运!对不起,但这有点超出我需要的范围,所以我不确定,但如果我遇到解决方案,我会在这里更新。也许检查您应用的所有沙盒设置是否包括文件访问、选择等? 别担心,你帮了大忙!刚刚发现如何使应用程序窗口全尺寸弹出。 :) 只是让它显示网站对我来说是一个巨大的胜利,而你在这方面发挥了重要作用。我想我会在 *** 上提出一些关于其余问题的问题。是的,据我所知,我已经启用了所有沙盒功能。周末好好休息! 【参考方案1】:我在使用 SwiftUI 的 MacOS 应用程序中遇到了与 WKWebView 完全相同的问题。
对我有用的解决方案是使用 GeometryReader 来获取确切的高度,并将 web 视图放在滚动视图中(我相信它与布局优先级计算有关,但无法触及核心还没有)。
这是对我有用的sn-p,也许它也对你有用
GeometryReader g in
ScrollView
BrowserView().tabItem
Text("Browser")
.frame(height: g.size.height)
.tag(1)
.frame(height: g.size.height)
【讨论】:
谢谢!愚蠢的是需要这种解决方法,但至少现在是这样。 希望有一种简单的方法可以在BrowserView
对象本身中获取它,但不是我能看到的,因为 NSViewRepresentable
不使用任意的 View
返回类型。跨度>
值得注意的是,当满足这两个条件时,通常会出现此问题: - Web 视图不是垂直的第一个视图 - 顶部容器视图大小是根据子视图布局和所需大小计算的至少在 SwiftUI 下一次复习之前我们还有一个工作要做:)
您好,请问这个 sn-p 放在哪里才能正常工作?
@esaruoho,用你的 WKWebView NSViewRepresentable 实例替换 BrowserView().tabItem Text("Browser")
【参考方案2】:
webView.edgesIgnoringSafeArea(.all)
似乎可以解决这个问题。
【讨论】:
【参考方案3】:@Ahmed 和GeometryReader
的解决方案非常优雅,但我找到了一个更短的解决方法。
struct BrowserView: View
// ...
var body: some View
// ...
browser.padding(-1.0)
// ...
似乎默认填充(等于 0)会导致此问题。 所以我把它设置为-1。
【讨论】:
以上是关于SwiftUI:WKWebView 在 macOS 上截断页面内容(NSViewRepresentable)的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SwiftUI 中观察 WKWebView 的加载进度?
如何在 SwiftUI 中为 WKWebView 创建浏览器选项卡