ios WKWebView setContentOffset不适用于animated = false:不发生滚动

ni65a41a  于 2023-05-02  发布在  iOS
关注(0)|答案(2)|浏览(123)

我正在尝试创建一个EPUB阅读器。由于EPUB中的章节被表示为没有分页符的完整HTML文件,我将在WKWebView中一次显示一页,加载loadHTMLString字符串。然后,当用户滑动到UIPageViewController的下一页时,我将创建一个新的WKWebView,并使用setContentOffset方法向下滚动一个页面。但是,setContentOffset方法对显示的内容没有影响。tldr -如何判断这个setContentOffset方法何时可以安全调用?
下面是我的页面视图控制器:

class MyPageViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {
    var page = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        dataSource = self
        delegate = self
        
        setViewControllers([Page(page: 0)], direction: .forward, animated: false, completion: nil)
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        return nil
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        return Page(page: page + 1)
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
        if completed {
            page += 1
        }
   }
}

下面是我的Page类:

class Page: UIViewController, WKNavigationDelegate, WKUIDelegate {
    var page: Int
    var webView: WKWebView!
    
    let testString = "<h1>00000000000000000000000000000000000000000000000000</h1><br><h1>11111111111111111111111111111111111111111111111111</h1><br><h1>22222222222222222222222222222222222222222222222222</h1><br><h1>33333333333333333333333333333333333333333333333333</h1><br><h1>44444444444444444444444444444444444444444444444444</h1><br><h1>55555555555555555555555555555555555555555555555555</h1><br><h1>66666666666666666666666666666666666666666666666666</h1><br><h1>77777777777777777777777777777777777777777777777777</h1><br><h1>88888888888888888888888888888888888888888888888888</h1><br><h1>99999999999999999999999999999999999999999999999999</h1>"

    init(page: Int) {
        self.page = page
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        webView = WKWebView(frame: view.bounds)
        webView.navigationDelegate = self
        
        view.addSubview(webView)
        
        load()
    }
    
    func load() {
        webView.loadHTMLString(testString, baseURL: nil)
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        self.scroll()
    }
    
    func scroll() {
        let scrollPoint = CGPoint(x: 0, y: 100 * CGFloat(page))
        webView.scrollView.setContentOffset(scrollPoint, animated: false)
    }
}

我希望滚动是即时的,这样用户就不会知道它在滚动,因此使用了animated: false。然而,这根本不会以任何方式改变视图。如果我使用animated: true,它可以正常工作,如果我将self.scroll() Package 在DispatchQueue.main.asyncAfter(deadline: .now() + 0.1)中,它也可以正常工作。但是如果我这样做的话,用户可能会看到一个不和谐的滚动。我试过调用.setNeedsLayout().layoutIfNeeded()都没有用;景色依旧没有改变。
所以很明显,有些东西还没有准备好滚动webView,即使在调用didFinish委托方法之后也是如此。我怎么知道这个webView什么时候可以滚动?或者还有其他原因导致animated: false不工作?

jm81lzqq

jm81lzqq1#

在研究了这个问题之后,我得出了与https://stackoverflow.com/a/76145772/8010366相似的结论。初始滚动似乎存在问题。
但是,如果您仍然需要在没有动画的情况下手动滚动,则可以使用以下低级代码:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    let yOffset = 20 * page
    webView.evaluateJavaScript("document.body.scrollTop = \(100 * yOffset)")
}

这将执行JavaScript代码来滚动HTML文档。此外,您应该添加更多内容以启用滚动。
希望这有帮助!
参考文献:

vatpfxk5

vatpfxk52#

我没有一个实际的答案,但这里有一些更多的信息
为了弄清楚这是怎么回事,我让de Page类成为webiew scrollView的委托。当这样做时,你可以看到在delegates scrollViewDidScroll事件中放置print时发生了一些奇怪的事情:

onSetContentOffset
didScroll (0.0, 100.0)
didScroll (0.0, 0.0)
didScroll (0.0, -102.0)
didScroll (0.0, 0.0)
didScroll (0.0, 518.3333333333334)
didScroll (0.0, 398.0)
didScroll (0.0, 0.0)

最初,偏移量 * 确实 * 被设置为100,但随后发生了一些奇怪的事情,偏移量在最终回到0之前到处都是。
如果你把animated设置为true,也会发生类似的事情,但是因为它是动画的,所以它会自动修复。

onSetContentOffset
didScroll (0.0, -118.0)
didScroll (0.0, 0.0)
didScroll (0.0, 0.6666666666666666)
didScroll (0.0, 0.0)
didScroll (0.0, 518.3333333333334)
didScroll (0.0, 398.0)
didScroll (0.0, 0.0)
didScroll (0.0, 2.0)
didScroll (0.0, 5.666666666666667)
didScroll (0.0, 10.333333333333334)
didScroll (0.0, 16.333333333333332)
didScroll (0.0, 23.666666666666668)
didScroll (0.0, 31.333333333333332)
didScroll (0.0, 39.666666666666664)
didScroll (0.0, 48.333333333333336)
didScroll (0.0, 57.0)
didScroll (0.0, 65.66666666666667)
didScroll (0.0, 73.66666666666667)
didScroll (0.0, 80.66666666666667)
didScroll (0.0, 87.0)
didScroll (0.0, 92.0)
didScroll (0.0, 96.0)
didScroll (0.0, 98.33333333333333)
didScroll (0.0, 99.33333333333333)

我不知道是什么原因造成的,也没有时间进一步调查。我最好的建议是接受动画卷轴或推迟它现在。如果你真的不想让别人看到你的行为,也许你可以把webView隐藏在一个正在加载的视图后面,直到所有的东西都被加载了。

相关问题