这个问题困扰了我一周
我的UI {Reviewable}具有自定义WKWebView
struct Webview : UIViewRepresentable {
var webview: WKWebView?
init() {
self.webview = WKWebView()
}
class Coordinator: NSObject, WKNavigationDelegate {
var parent: Webview
init(_ parent: Webview) {
self.parent = parent
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("Loading finished -- Delegate")
webView.evaluateJavaScript("document.documentElement.scrollHeight", completionHandler: { (height, error) in
print(height)
webView.bounds.size.height = height as! CGFloat
})
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> WKWebView {
return webview!
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.navigationDelegate = context.coordinator
let htmlStart = "<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, shrink-to-fit=no\"></HEAD><BODY>"
let htmlEnd = "</BODY></HTML>"
let dummy_html = """
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut venenatis risus. Fusce eget orci quis odio lobortis hendrerit. Vivamus in sollicitudin arcu. Integer nisi eros, hendrerit eget mollis et, fringilla et libero. Duis tempor interdum velit. Curabitur</p>
<p>ullamcorper, nulla nec elementum sagittis, diam odio tempus erat, at egestas nibh dui nec purus. Suspendisse at risus nibh. Mauris lacinia rutrum sapien non faucibus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec interdum enim et augue suscipit, vitae mollis enim maximus.</p>
<p>Fusce et convallis ligula. Ut rutrum ipsum laoreet turpis sodales, nec gravida nisi molestie. Ut convallis aliquet metus, sit amet vestibulum risus dictum mattis. Sed nec leo vel mauris pharetra ornare quis non lorem. Aliquam sed justo</p>
"""
let htmlString = "\(htmlStart)\(dummy_html)\(htmlEnd)"
uiView.loadHTMLString(htmlString, baseURL: nil)
}
}
它是这样显示的
,这里的问题是webview缺少高度。
除非我添加一个硬编码的frame
值,否则它不会出现在我的视图中
我的内容被截断了。
Webview()
.frame(height:300)
我几乎碰到了类似的问题,但这没有帮助:/
答案 0 :(得分:17)
在SwiftUI中ScrollView
和UIWebView
内部UIScrollView
都在试图从父级视图中获取大小,这令人困惑。 / p>
因此这是一种可行的方法..将确定的大小从Web视图传递到SwiftUI世界,因此不使用硬编码,并且ScrollView
的行为就像具有扁平内容。
根据我的理解和模拟,在结果的第一个演示中...
这是演示的完整模块代码。 经过测试并在Xcode 11.2 / iOS 13.2上工作。
import SwiftUI
import WebKit
struct Webview : UIViewRepresentable {
@Binding var dynamicHeight: CGFloat
var webview: WKWebView = WKWebView()
class Coordinator: NSObject, WKNavigationDelegate {
var parent: Webview
init(_ parent: Webview) {
self.parent = parent
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript("document.documentElement.scrollHeight", completionHandler: { (height, error) in
DispatchQueue.main.async {
self.parent.dynamicHeight = height as! CGFloat
}
})
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> WKWebView {
webview.scrollView.bounces = false
webview.navigationDelegate = context.coordinator
let htmlStart = "<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, shrink-to-fit=no\"></HEAD><BODY>"
let htmlEnd = "</BODY></HTML>"
let dummy_html = """
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut venenatis risus. Fusce eget orci quis odio lobortis hendrerit. Vivamus in sollicitudin arcu. Integer nisi eros, hendrerit eget mollis et, fringilla et libero. Duis tempor interdum velit. Curabitur</p>
<p>ullamcorper, nulla nec elementum sagittis, diam odio tempus erat, at egestas nibh dui nec purus. Suspendisse at risus nibh. Mauris lacinia rutrum sapien non faucibus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec interdum enim et augue suscipit, vitae mollis enim maximus.</p>
<p>Fusce et convallis ligula. Ut rutrum ipsum laoreet turpis sodales, nec gravida nisi molestie. Ut convallis aliquet metus, sit amet vestibulum risus dictum mattis. Sed nec leo vel mauris pharetra ornare quis non lorem. Aliquam sed justo</p>
"""
let htmlString = "\(htmlStart)\(dummy_html)\(htmlEnd)"
webview.loadHTMLString(htmlString, baseURL: nil)
return webview
}
func updateUIView(_ uiView: WKWebView, context: Context) {
}
}
struct TestWebViewInScrollView: View {
@State private var webViewHeight: CGFloat = .zero
var body: some View {
ScrollView {
VStack {
Image(systemName: "doc")
.resizable()
.scaledToFit()
.frame(height: 300)
Divider()
Webview(dynamicHeight: $webViewHeight)
.padding(.horizontal)
.frame(height: webViewHeight)
}
}
}
}
struct TestWebViewInScrollView_Previews: PreviewProvider {
static var previews: some View {
TestWebViewInScrollView()
}
}
答案 1 :(得分:3)
如果我只是将您的Webview
放在VStack
中,它的大小将达到预期。那里没有实际的问题。
尽管您没有这么说,但Webview
不占用任何空间的最可能原因是您已将这些项目放置在ScrollView
中。由于WKWebView
基本上是UIScrollView
的子集(虽然不是其子类),所以当包含在另一个滚动视图中时,系统不知道如何调整其大小。
例如:
struct ContentView: View {
var body: some View {
NavigationView {
ScrollView { // THIS LINE means that...
VStack(spacing: 0.0) {
Color.red.aspectRatio(1.0, contentMode: .fill)
Text("Lorem ipsum dolor sit amet").fontWeight(.bold)
Webview()
.frame(height: 300) // ...THIS is necessary
}
}
.navigationBarItems(leading: Text("Item"))
.navigationBarTitle("", displayMode: .inline)
}
}
}
嵌套滚动视图并不是您想要显示的布局所需要的。毫无疑问,您希望WKWebView
滚动时顶部的图像和文本不会滚动。
您需要使用UIKit或SwiftUI的技术将是相似的。我目前不建议在SwiftUI上执行此操作。
WKWebView
放在容器中(很可能是UIViewController.view
)UIHostingContainer
中)放置为该视图中的兄弟,位于网络视图上方。webView.scrollView.contentInset.top
设置为#2中内容的大小UIScrollViewDelegate.scrollViewDidScroll()
scrollViewDidScroll
中,修改内容的位置以匹配网络视图的contentOffset
。这是一种可能的实现方式:
WebView:
import SwiftUI
import WebKit
struct WebView : UIViewRepresentable {
@Binding var offset: CGPoint
var contentInset: UIEdgeInsets = .zero
class Coordinator: NSObject, UIScrollViewDelegate {
var parent: WebView
init(_ parent: WebView) {
self.parent = parent
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
var offset = scrollView.contentOffset
offset.y += self.parent.contentInset.top
self.parent.offset = offset
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> WKWebView {
let webview = WKWebView()
webview.scrollView.delegate = context.coordinator
// continue setting up webview content
return webview
}
func updateUIView(_ uiView: WKWebView, context: Context) {
if uiView.scrollView.contentInset != self.contentInset {
uiView.scrollView.contentInset = self.contentInset
}
}
}
ContentView。注意:我使用50
作为常量而不是计算大小。不过,可以使用GeometryReader
来获取实际大小。
struct ContentView: View {
@State var offset: CGPoint = .zero
var body: some View {
NavigationView {
WebView(offset: self.$offset, contentInset: UIEdgeInsets(top: 50, left: 0, bottom: 0, right: 0))
.overlay(
Text("Hello World!")
.frame(height: 50)
.offset(y: -self.offset.y)
, alignment: .topLeading)
.edgesIgnoringSafeArea(.all)
}
.navigationBarItems(leading: Text("Item"))
.navigationBarTitle("", displayMode: .inline)
}
}