SwiftUI:WKWebView 在 macOS 上截断页面内容(NSViewRepresentable)
SwiftUI: WKWebView Cutting Off Page Content on macOS (NSViewRepresentable)
我有 WKWebView
的基本 NSViewRepresentable
实现,用于 macOS 上的 SwiftUI 应用程序。 UIViewRepresentable
等效项在 iOS 上运行良好,但在 macOS(本机,而不是 Catalyst)上,顶部内容总是被截断。
丢失的量始终等于父视图(例如选项卡视图)的大小及其填充,这表明网络视图不断将其内容缩放到 window 尺寸,而不是 view 尺寸。
例如,这个页面:
...应该如下(如Chrome所示)。整个导航栏都被裁掉了(尽管两侧似乎没有受到影响)。
关于如何解决这个问题有什么建议吗?有趣的是,如果我在选项卡之间来回切换,内容会正确显示约 1 秒,然后调整内容大小,使其再次被截断。这让我觉得 updateNSView
方法需要一些东西,但我不确定是什么。
似乎是与 here 讨论的问题类似的问题,但那是针对基于 IB 的应用程序,我看不到将其应用于 SwiftUI 的方法。
使用的代码如下。注意:Web 视图保留为 属性,因此可以通过其他方法(例如触发页面加载、刷新、返回等)引用它
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://whosebug.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()
}
}
我在使用 SwiftUI 的 MacOS 应用程序中遇到了与 WKWebView 完全相同的问题。
对我有用的解决方案是使用 GeometryReader 获取确切的高度,并将 web view 放在 scrollview 中(我相信它与布局优先级计算有关,但无法到达它的核心)。
这是对我有用的片段,也许对你也有用
GeometryReader { g in
ScrollView {
BrowserView().tabItem {
Text("Browser")
}
.frame(height: g.size.height)
.tag(1)
}.frame(height: g.size.height)
}
webView.edgesIgnoringSafeArea(.all)
似乎可以解决这个问题。
@Ahmed GeometryReader
的解决方案非常优雅,但我找到了一个更短的解决方法。
struct BrowserView: View {
// ...
var body: some View {
// ...
browser.padding(-1.0)
// ...
}
}
似乎是等于 0 的默认填充导致了此问题。
所以我只是将它设置为-1.
我有 WKWebView
的基本 NSViewRepresentable
实现,用于 macOS 上的 SwiftUI 应用程序。 UIViewRepresentable
等效项在 iOS 上运行良好,但在 macOS(本机,而不是 Catalyst)上,顶部内容总是被截断。
丢失的量始终等于父视图(例如选项卡视图)的大小及其填充,这表明网络视图不断将其内容缩放到 window 尺寸,而不是 view 尺寸。
例如,这个页面:
...应该如下(如Chrome所示)。整个导航栏都被裁掉了(尽管两侧似乎没有受到影响)。
关于如何解决这个问题有什么建议吗?有趣的是,如果我在选项卡之间来回切换,内容会正确显示约 1 秒,然后调整内容大小,使其再次被截断。这让我觉得 updateNSView
方法需要一些东西,但我不确定是什么。
似乎是与 here 讨论的问题类似的问题,但那是针对基于 IB 的应用程序,我看不到将其应用于 SwiftUI 的方法。
使用的代码如下。注意:Web 视图保留为 属性,因此可以通过其他方法(例如触发页面加载、刷新、返回等)引用它
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://whosebug.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()
}
}
我在使用 SwiftUI 的 MacOS 应用程序中遇到了与 WKWebView 完全相同的问题。
对我有用的解决方案是使用 GeometryReader 获取确切的高度,并将 web view 放在 scrollview 中(我相信它与布局优先级计算有关,但无法到达它的核心)。
这是对我有用的片段,也许对你也有用
GeometryReader { g in
ScrollView {
BrowserView().tabItem {
Text("Browser")
}
.frame(height: g.size.height)
.tag(1)
}.frame(height: g.size.height)
}
webView.edgesIgnoringSafeArea(.all)
似乎可以解决这个问题。
@Ahmed GeometryReader
的解决方案非常优雅,但我找到了一个更短的解决方法。
struct BrowserView: View {
// ...
var body: some View {
// ...
browser.padding(-1.0)
// ...
}
}
似乎是等于 0 的默认填充导致了此问题。 所以我只是将它设置为-1.