iOS WebView自适应高度(ScrollView嵌套滚动)

  本方案通过重写手势滚动代码,解决了 ScrollViewTableView 的嵌套滚动问题。同时通过障眼法的方案实现了 WKWebView 的高度自适应。

2023 - 8 - 31 解决滚动不丝滑的问题
在设置 contentOffset.y 时使用动画

 // 例如
UIView.animate(withDuration: 0.05, delay: 0, options: .init(arrayLiteral: [.beginFromCurrentState,.allowUserInteraction])) { [weak self] in
   self?.webView.scrollView.contentOffset.y = newOffsetY
}

UIView.animate(withDuration: 0.05, delay: 0, options: .init(arrayLiteral: [.beginFromCurrentState,.allowUserInteraction])) { [weak self] in
   self?.tableView.contentOffset.y = newOffsetY
}

使用该动画会使滚动变得流畅,但会导致滚动时不能及时跟手

Demo 在这 Demo
请使用 ViewController2 进行测试,Demo中并未加入【解决滚动不丝滑的问题】的代码,可自行添加
前边废话比较多,可以直接看 【第三节 - 方案实现

觉得有用就点个赞支持一下,嘻

一、发现问题

  最近测试告知我们的文章页面有几率出现显示不全的问题,拿自己的手机跑了几十遍才复现了一次。原因是 WKWebView 的高度设置错误。

  我们的文章页面采用 TableView 嵌套 WebView 的方式实现。

  WebView 为第一个 Cell,将其设置为禁止滚动。然后将它的 frame高度设置为与ContentSize 高度相同。这样可以实现滚动完文章后显示下边的 Cell 评论。而原本的逻辑为在 WebView 调用 DidFinish 后,将 WebView 所在的 Cell 高度设置为它内部 ContentSize的高度,然后刷新一下 TableView 即可实现高度自适应。

  但是出现问题的原因为 WebView 在调用 DidFinish 的时候有可能页面还没完全的渲染完毕,这时获取 ContentSize 就是错误的高度。

  解决该问题最简单的方法就是通过 KVO 监听其内部 ScrollViewContentSize 改变。每次改变就更新一下 WebView 的高度。

  但这样还会产生另一个问题,由于我们修改的是 WebView 本身 Frame 的高度,当新页面的 ContentSize 高度低于 WebView 的高度时,KVO 就不会更新 ContentSize 。也就是说,当你进入一个特别长的网页后,再跳转到短一点的网页会出现底部留有大片空白的问题。

  这个问题是非常影响用户体验的,所以我开始调研解决该问题的方法。

二、方案调研

  先说最终的方案理论,首先将 WebView 的高度设置为手机屏幕的高度(有导航栏的去除导航栏高度),然后将 WebView 设置为 TableView 的子 View,或者设置为 headerCell 都可以。然后我们自己控制 WebViewTableView 的滚动。因为进入页面后优先显示网页,当网页滚动到底部时列表才会滚动,在视觉上就会认为网页和列表是连在一起的,这样就达成了我们的目的。

  所以我们需要专门去写一层手势控制,用手势去控制 WebViewTableView 的联动。

  类似于分页的手势嵌套,不过不一样的是,分页的手势嵌套是 TableViewScrollView 上方,虽然表面上是 TableView 在滚动,实际上两者的 frame 都没有发生变化。而 TableView 嵌套 WebView 会出现 WebView 滚动出屏幕的情况,这时候原本的手势就不会作用在 WebView 上,就导致当我们 TableView 滚动到顶部时,由于手势穿透没有作用于 WebView 从而出现手势中断的问题。

方案调研流程,不想看的可以跳过。

  首先我发现将 WebViewSize 设置为 Zero 后再刷新一下 WebView,就可以重新监听到 ContentSize 的改变。但会造成一次屏幕的闪烁,不过影响不大,用户在视觉效果上会认为是网页的加载。我只需要知道页面什么时候跳转或者改变,就可以控制刷新的时机,于是我把调研的重点放在了监听页面的变化。


  我认为,既然网页是在点击某个按钮后进行的跳转,那在网页加载的时候刷新一下高度不就可以了。然后我对 estimatedProgress 进行了监听,在页面加载完成后通过上面的方法刷新一下 WebView

  经过实验,这种方式确实可以实现高度的修改。但又出现了一个新的问题,大部分的页面都是通过 URL 的跳转完成的,监听页面加载确实没有问题。但还有一种是在页面内进行的分页,页面内部进行上一页下一页的跳转时,依然会造成高度变高后无法缩小的问题,并且由于并没有发生 URL 跳转我们也无法监听到。

  所以这种方案还有些缺陷。


  于是我想,如果网页在点击按钮跳转时通过 js 回调给我们呢,经过询问发现我们的所有文章网页都是通过第三方工具生成的,也就是说没办法在里边增加 js 回调,那么这个方案也不大行。


  既然网页不能回调给我,那我能不能对网页中的按钮添加监听呢,当网页加载完毕后对所有的按钮增加监听,当用户点击按钮时进行 js 回调,收到回调后我再刷新页面。有了这个想法后我去查找相关的代码,找到了注册 js 标签监听的方法,于是我添加对

你可能感兴趣的:(iOS WebView自适应高度(ScrollView嵌套滚动))