问题描述
我使用此代码将html
中的文本加载到WKWebView
文件中:
do {
guard let filePath = Bundle.main.path(forResource: "\(readBookNumber)",ofType: "html")
else {
print ("File reading error")
return
}
var content = try String(contentsOfFile: filePath,encoding: .utf8)
let baseUrl = URL(fileURLWithPath: filePath)
content.changeHtmlStyle(font: "Iowan-Old-Style",fontSize: UserDefaults.standard.integer(forKey: "textSize"),fontColor: textColor)
webView.loadHTMLString(headerString+content,baseURL: baseUrl)
}
catch {
print ("File HTML error")
}
self.webView.scrollView.contentOffset.x = CGFloat(UserDefaults.standard.integer(forKey: "pagetoLoad"))
func webView(_ webView: WKWebView,didFinish navigation: WKNavigation!) {
dispatchQueue.main.asyncAfter(deadline: .Now() + 0.5) {
self.webView.scrollView.contentOffset.x = CGFloat(UserDefaults.standard.integer(forKey: "pagetoLoad"))
}
}
起初,我使用了deadline: .Now() + 0.1
,但这没用。因为最后读取的页面是最初加载的,所以几秒钟后,我在第一页上看到了我的文本。我将其更改为deadline: .Now() + 0.5
,并且从读取的最后一页开始加载文本。是700页。但是现在我想加载1700页的其他文本。我也有像第一次一样的问题。我可以更改deadline: .Now() + 1.0
,并且我的文本可以正常加载。但是我认为这不是最好的解决方案。我在iPhone X上运行它。但是也许如果在iPad mini 2上运行它,则应该更改deadline: .Now() + 10.0
,因为iPad mini 2的功能不是很强大。如何解决问题?
根据@DPrice代码进行更新:
如果我使用此代码:
override func viewDidLoad() {
super.viewDidLoad()
webView.addobserver(self,forKeyPath: #keyPath(WKWebView.estimatedProgress),options: .new,context: nil)
....
}
override func observeValue(forKeyPath keyPath: String?,of object: Any?,change: [NSkeyvalueChangeKey : Any]?,context: UnsafeMutableRawPointer?) {
if (keyPath == "estimatedProgress") {
if webView.estimatedProgress == 1.0 {
self.webView.scrollView.contentOffset.x = CGFloat(UserDefaults.standard.integer(forKey: "pagetoLoad\(self.readBookNumber)"))
}
}
}
我的代码中有同样糟糕的结果。
但是,如果我使用以下代码:
override func observeValue(forKeyPath keyPath: String?,context: UnsafeMutableRawPointer?) {
if (keyPath == "estimatedProgress") {
if webView.estimatedProgress == 1.0 {
dispatchQueue.main.asyncAfter(deadline: .Now() + 0.5) {
self.webView.scrollView.contentOffset.x = CGFloat(UserDefaults.standard.integer(forKey: "pagetoLoad\(self.readBookNumber)"))
}
}
}
}
一切正常。我的最后一页加载正常。但这并不能解决我的问题。
解决方法
您可以添加属性观察器并查看页面加载的估计进度:
override func viewDidLoad() {
super.viewDidLoad()
webView.addObserver(self,forKeyPath: #keyPath(WKWebView.estimatedProgress),options: .new,context: nil)
....
}
并观察页面何时加载:
override func observeValue(forKeyPath keyPath: String?,of object: Any?,change: [NSKeyValueChangeKey : Any]?,context: UnsafeMutableRawPointer?) {
if (keyPath == "estimatedProgress") {
if webView.estimatedProgress == 1.0 {
print ("page loaded")
}
}
}
您也许可以根据页码来预测设置偏移量之前需要执行的加载过程。
,这是ViewController
类的修改版本:
import UIKit
import WebKit
class ViewController: UIViewController,UIScrollViewDelegate,WKNavigationDelegate {
@IBOutlet weak var webView: WKWebView!
@IBOutlet weak var pagesLabel: UILabel!
var readBookNumber = 0
let headerString = "<meta name=\"viewport\" content=\"initial-scale=1.0\" />"
var textSize = 3
var contentSize: CGSize = .zero
override func viewDidLoad() {
super.viewDidLoad()
// Web View Delegate
webView.scrollView.delegate = self
webView.navigationDelegate = self
webView.scrollView.isPagingEnabled = true
webView.scrollView.alwaysBounceVertical = false
webView.scrollView.showsHorizontalScrollIndicator = true
webView.scrollView.showsVerticalScrollIndicator = false
webView.scrollView.panGestureRecognizer.isEnabled = false
webView.scrollView.pinchGestureRecognizer?.isEnabled = false
webView.scrollView.bouncesZoom = false
self.webView.isOpaque = false;
self.webView.backgroundColor = .clear
// Load File
do {
guard let filePath = Bundle.main.path(forResource: "0",ofType: "html")
else {
print ("File reading error")
return
}
var content = try String(contentsOfFile: filePath,encoding: .utf8)
let baseUrl = URL(fileURLWithPath: filePath)
content.changeHtmlStyle(font: "Iowan-Old-Style",fontSize: 4,fontColor: "black")
webView.loadHTMLString(headerString+content,baseURL: baseUrl)
// add content size Observer
webView.scrollView.addObserver(self,forKeyPath: #keyPath(UIScrollView.contentSize),context: nil)
}
catch {
print ("File HTML error")
}
}
override func observeValue(forKeyPath keyPath: String?,context: UnsafeMutableRawPointer?) {
if (keyPath == #keyPath(UIScrollView.contentSize)) {
let contentSize = webView.scrollView.contentSize
if contentSize != self.contentSize {
self.contentSize = contentSize
DispatchQueue.main.async {
self.webView.scrollView.contentOffset.x = CGFloat(UserDefaults.standard.integer(forKey: "pageToLoad"))
}
}
}
}
// MARK: - webView Scroll View
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
self.stoppedScrolling()
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView,willDecelerate decelerate: Bool) {
if !decelerate {
self.stoppedScrolling()
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
var currentPage = Int((webView.scrollView.contentOffset.x / webView.scrollView.frame.size.width) + 1)
let pageCount = Int(webView.scrollView.contentSize.width / webView.scrollView.frame.size.width)
if currentPage == 0 {
currentPage = 1
} else {
}
if !webView.isHidden {
pagesLabel.text = "\( currentPage ) из \( pageCount )"
} else {
pagesLabel.text = ""
}
}
func scrollViewWillBeginZooming(_ scrollView: UIScrollView,with view: UIView?) {
webView.scrollView.pinchGestureRecognizer?.isEnabled = false
}
func stoppedScrolling() {
let pageToLoad = Int((webView.scrollView.contentOffset.x))
UserDefaults.standard.set(pageToLoad,forKey: "pageToLoad")
}
// MARK: - loading webView
func webView(_ webView: WKWebView,didStartProvisionalNavigation navigation: WKNavigation!) {
}
func webView(_ webView: WKWebView,didFinish navigation: WKNavigation!) {
// Маленькая задержка,которую мне хотелось бы использовать
/*DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.webView.scrollView.contentOffset.x = CGFloat(UserDefaults.standard.integer(forKey: "pageToLoad"))
}*/
// Большая задержка,которую мне приходится использовать
// don't do this here... we'll do the "auto-scroll" inside the change contentSize Observer
//DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
// self.webView.scrollView.contentOffset.x = CGFloat(UserDefaults.standard.integer(forKey: "pageToLoad"))
//}
}
func webView(_ webView: WKWebView,didFail navigation: WKNavigation!,withError error: Error) {
}
}
extension String {
mutating func changeHtmlStyle(font: String,fontSize: Int,fontColor: String) {
let style = "<font face='\(font)' size='\(fontSize)' color= '\(fontColor)'>%@"
self = String(format: style,self)
}
}
它使用观察器来观察Web视图的滚动视图中的contentSize
更改。
请注意,在加载和布局过程中会多次调用它(使用不同的值),但这可能为您完成工作。
但是,还请注意,您需要考虑网络视图尺寸的变化-例如,如果用户旋转设备。所以...还有更多事情要做,但这可能会让您前进。
,您应该观察WKWebView.estimatedProgress
而不是观察UIScrollView.contentSize
,因为您需要滚动到可用位置,例如:
var positionY: CGFloat = 1000
var contentSize = CGSize(width: 0,height: 0)
override func viewDidLoad() {
super.viewDidLoad()
...
webView?.scrollView.addObserver(self,context: nil)
}
override func observeValue(forKeyPath keyPath: String?,context: UnsafeMutableRawPointer?) {
if (keyPath == #keyPath(UIScrollView.contentSize)) {
if let contentSize = webView?.scrollView.contentSize,contentSize != self.contentSize {
self.contentSize = contentSize
if contentSize.height > positionY {
webView?.scrollView.setContentOffset(CGPoint(x: 0,y: positionY),animated: true)
}
}
}
}