如何解决WKWebView内容高度值较小的问题?

3

我正在使用WebView加载HTML内容。

当我在WebView中加载HTML内容时,它会正确显示。但是当我使用新的HTML内容刷新WebView时,问题就出现了。

例如:我的第一个HTML内容高度为900,它可以正确显示,然后我重新加载WebView,将其与高度为400的新HTML内容一起使用,但WebView不会缩小并适应新高度的内容。它仍然保持原来的900高度。

因此,似乎WebView能够从先前加载的较少内容重新调整大小以适应较多内容,但无法在新内容比先前加载的内容少时重新调整大小。

WebView

struct WebView: UIViewRepresentable {
    @State var htmlString: String
    @Binding var dynamicHeight: CGFloat

    func makeUIView(context: Context) -> WKWebView {
        let webView: WKWebView = WKWebView()
        webView.navigationDelegate = context.coordinator
        webView.scrollView.bounces = false
        webView.backgroundColor = .clear
        return webView
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
        uiView.loadHTMLString(htmlString, baseURL: nil)
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, WKNavigationDelegate {
        var parent: WebView

        init(_ parent: WebView) {
            self.parent = parent
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            webView.evaluateJavaScript("document.readyState", completionHandler: { (complete, error) in
                if complete != nil {
                   webView.evaluateJavaScript("document.documentElement.scrollHeight", completionHandler: { (result, error) in
                            if let height = result as? CGFloat {
                                self.parent.dynamicHeight = height
                            }
                    })
                }
            })
        }
    }
}

任何我使用 WebView 的内容

struct WebTest: View {

    @ObservedObject var viewModel = NewsVM()
    @State var index: Int = 0
    @State var newID: String = ""
    let screen = UIScreen.main.bounds
    let formatString = "<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0\"><script type=\"text/javascript\" src=\"https://platform.twitter.com/widgets.js\"></script><style>@media (prefers-color-scheme: dark) { body { background-color: #1c1c1e; color: white; }} img,iframe,blockquote {\n\t\t\tmax-width: \(UIScreen.main.bounds.width - 24);\n\t\t\theight: auto\n\t\t}\n\t\t</style></head><body><span style=\"font-family: '-apple-system', 'HelveticaNeue'; font-size:17\">%@</span></body></html>"
    @State private var webViewHeight: CGFloat = .zero

    init(id:String) {
        viewModel.fetchNews(id: id)
        self.newID = id
    }

    var body: some View {
        Group{
            if self.viewModel.news.count > 0 {
                        ModelPages(self.viewModel.news, currentPage: self.$index, wrap: false, hasControl: false) { pageIndex, new in
                        ScrollView(.vertical, showsIndicators: false){
                            Text("Height: \(self.webViewHeight)").padding()
                            WebView(htmlString: String(format: self.formatString, new.content), dynamicHeight: self.$webViewHeight)
                                    .frame(width: self.screen.width - 16)
                                    .frame(height: self.webViewHeight)
                                    .tag(pageIndex)
                                    .padding(.horizontal, 8)
                            }
                        }
            }else{
                Group{
                    if self.viewModel.error == true{
                        ConnectionError()
                    }else{
                        LoadingView()
                    }
                }
            }
        }
    }
}
3个回答

2

我在collectionView中包含手风琴,WKWebView中的可展开Web数据遇到了类似的问题。由于最后一个可展开的Web项,它无法滚动到底部,我使用以下解决方案解决了这个问题:

class WebViewCollectionViewCell: WKNavigationDelegate {
    @IBOutlet private var webView: WKWebView!
    
    private var cancellable: AnyCancellable?
    var onWebViewFinished: ((CGFloat) -> Void)?
    
    func webView(_: WKWebView, didFinish _: WKNavigation!) {
        webView.contentHeight { [weak self] height in
            self?.onWebViewFinished?(height)
            UIView.animate(withDuration: 0.4) {
                self?.webView.alpha = 1 // Fix white flashing
            }
        }
        cancellable = webView?
            .publisher(for: \.scrollView.contentSize)
            .removeDuplicates()
            .sink { [weak self] size in
                self?.onWebViewFinished?(size.height)
            }
    }
}

extension WKWebView {
    func contentHeight(completion: @escaping ((CGFloat) -> Void)) {
        evaluateJavaScript("document.readyState") { [weak self] complete, _ in
            if complete.exists {
                self?.evaluateJavaScript("document.body.scrollHeight", completionHandler: { height, _ in
                    completion(height as? CGFloat ?? 0)
                })
            }
        }
    }
}

同时使用UICollectionViewCell闭包的方法:

class ViewController: 
 UIViewController, 
 UICollectionViewDelegate,
 UICollectionViewDataSource,
 UICollectionViewDelegateFlowLayout {

private var webViewHeight: CGFloat = 1_000
private lazy var configurator: CollectionViewCell = {
  cell.onWebViewFinished = { height in
                self?.webViewHeight = height
                self?.onWebViewFinished?()
            }
            return cell
    }

1
我从这个解决方案开始解决这个问题:https://dev59.com/Fl4c5IYBdhLWcg3wzs-Q#41511422
  1. 监视onresize事件,但添加以下内容。

  2. 在ondocument ready事件、body末尾添加/inject一个<span id="endElement"></span>

  3. 获取span-endElement Y以获取“真实”高度。
  4. 将结果高度放置在webView.frame.Height上。

使用AddUserScript()注入的函数onloadFunction。

window.onload=function () {window.webkit.messageHandlers.sizeNotification.postMessage({justLoaded:true,height: document.body.scrollHeight,endElement:document.getElementById('endOfDocument').offsetTop});};

onresize

document.body.onresize=function() {window.webkit.messageHandlers.sizeNotification.postMessage({justLoaded:false,height: document.body.scrollHeight,endElement:document.getElementById('endOfDocument').offsetTop});};

在结尾处插入
document.body.insertAdjacentHTML('beforeend',"<span style='height: 0;' id='endOfDocument'></span>" );

你在最后是什么意思?@Jaekov Segovia。你把它注射在哪里? - Jalil
@Jalil 动态地将一个HTML元素添加到'body'的末尾。这样,您可以获取该元素在body中的属性。 - Jaekov Segovia

0

你可以尝试将Webview放在一个父级UIView中,并加载页面。不要为UIView设置固定的高度约束,而是让Webview定义父级UIView的高度。这样或许会起作用。


我将webview包装在一个group中,并为group定义了动态高度,但它仍然保持不变。当我没有为其定义任何高度时,动态高度的值正常工作,但是当我将其定义为任何视图时,它无法正常工作。 - Halil İbrahim YÜCE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接