我正在努力向我的浏览器应用程序添加新的阅读视图。它是另一个视图控制器,仅包含作为子视图添加的 WKWebView,并带有用于关闭视图的按钮(和手势)。一切都很好,但是当我旋转设备时,子视图的大小没有调整,所以我的屏幕的一半是空的。
阅读视图中的 WKWebView 获取主视图控制器的 URL,并在用户点击主视图控制器上的按钮后执行 Segue,并且该 URL 存储为网页 URL。
这是我使用的代码:
import UIKit
import WebKit
class ReadingViewController: UIViewController, UIGestureRecognizerDelegate, WKNavigationDelegate, WKScriptMessageHandler {
@IBOutlet weak var _closeButton: UIButton!
@IBOutlet weak var _progressView: UIProgressView!
@IBOutlet weak var _loadingErrorView: UIView!
var webpageURL: NSURL?
var _webView: WKWebView?
var _isMainFrameNavigationAction: Bool?
var _loadingTimer: NSTimer?
var _swipeFromTopRecognizer: UIScreenEdgePanGestureRecognizer?
var _panFromRightRecognizer: UIScreenEdgePanGestureRecognizer?
var _panFromLeftRecognizer: UIScreenEdgePanGestureRecognizer?
var _errorView: UIView?
var _isCurrentPageLoaded = false
var _progressTimer: NSTimer?
var _isWebViewLoading = false
override func viewDidLoad() {
super.viewDidLoad()
var contentController = WKUserContentController();
var scaleToFit = WKUserScript(source: "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);", injectionTime: WKUserScriptInjectionTime.AtDocumentStart, forMainFrameOnly: true)
contentController.addUserScript(scaleToFit)
contentController.addScriptMessageHandler(self, name: "callbackHandler")
var webViewConfiguration: WKWebViewConfiguration = WKWebViewConfiguration()
webViewConfiguration.allowsInlineMediaPlayback = true
webViewConfiguration.mediaPlaybackRequiresUserAction = false
_webView = WKWebView(frame: self.view.frame, configuration: webViewConfiguration)
self.view.addSubview(_webView!)
_webView!.navigationDelegate = self
self.view.sendSubviewToBack(_webView!)
_webView!.allowsBackForwardNavigationGestures = true
_loadingErrorView.hidden = true
_swipeFromTopRecognizer = UIScreenEdgePanGestureRecognizer(target: self, action: Selector("handleSwipeFromTop:"))
_swipeFromTopRecognizer!.edges = UIRectEdge.Top
_swipeFromTopRecognizer!.delegate = self
self.view.addGestureRecognizer(_swipeFromTopRecognizer!)
_progressView.hidden = true
var urlAsString = "\(webpageURL!)"
loadURL(urlAsString)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// UI Control Functions
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
@IBAction func closeReadingView(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
func closeButtonEnabled(bool:Bool) {
_closeButton.enabled = bool
}
func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
if(message.name == "callbackHandler") {
println("JavaScript is sending a message \(message.body)")
}
}
// WebView Functions
func webView(webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
_loadingErrorView.hidden = true
_isWebViewLoading = true
_progressView.hidden = false
_progressView.progress = 0
_progressTimer = NSTimer.scheduledTimerWithTimeInterval(0.01667, target: self, selector: "progressTimerCallback", userInfo: nil, repeats: true)
_loadingTimer = NSTimer.scheduledTimerWithTimeInterval(30, target: self, selector: "loadingTimeoutCallback", userInfo: nil, repeats: false)
}
func loadingTimeoutCallback() {
_webView?.stopLoading()
handleWebViewError()
}
func webView(webView: WKWebView, didCommitNavigation navigation: WKNavigation!) {
_isCurrentPageLoaded = true
_loadingTimer!.invalidate()
_isWebViewLoading = false
if self._webView!.URL == webpageURL! {
handleWebViewError()
println(webpageURL!)
println(self._webView!.URL!)
} else {
println("Page was loaded successfully")
println(webpageURL!)
println(self._webView!.URL!)
}
}
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
_isCurrentPageLoaded = true
_loadingTimer!.invalidate()
_isWebViewLoading = false
}
func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) {
if let newFrameLoading = _isMainFrameNavigationAction {
} else {
handleWebViewError()
}
}
func webView(webView: WKWebView, didFailNavigation navigation: WKNavigation!, withError error: NSError) {
if let newFrameLoading = _isMainFrameNavigationAction {
} else {
handleWebViewError()
}
}
func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {
if (navigationAction.targetFrame == nil && navigationAction.navigationType == .LinkActivated) {
_webView!.loadRequest(navigationAction.request)
}
_isMainFrameNavigationAction = navigationAction.targetFrame?.mainFrame
decisionHandler(.Allow)
}
func handleWebViewError() {
_loadingTimer!.invalidate()
_isCurrentPageLoaded = false
_isWebViewLoading = false
displayLoadingErrorMessage()
}
func progressTimerCallback() {
if (!_isWebViewLoading) {
if (_progressView.progress >= 1) {
_progressView.hidden = true
_progressTimer?.invalidate()
} else {
_progressView.progress += 0.2
}
} else {
_progressView.progress += 0.003
if (_progressView.progress >= 0.95) {
_progressView.progress = 0.95
}
}
}
func loadURL(urlString: String) {
let addrStr = httpifyString(urlString)
let readingAddr = addrStr.stringByAddingPercentEncodingForFormUrlencoded()!
let addr = NSURL(string: "http://mobilizer.instapaper.com/m?u=\(readingAddr)")
if let webAddr = addr {
let req = NSURLRequest(URL: webAddr)
_webView!.loadRequest(req)
} else {
displayLoadingErrorMessage()
}
}
func httpifyString(str: String) -> String {
let lcStr:String = (str as NSString).lowercaseString
if (count(lcStr) >= 7) {
if (lcStr.rangeOfString("http://") != nil) {
return str
} else if (lcStr.rangeOfString("https://") != nil) {
return str
}
}
return "http://"+str
}
func displayLoadingErrorMessage() {
_loadingErrorView.hidden = false
}
func handleGoBackPan(sender: UIScreenEdgePanGestureRecognizer) {
if (sender.state == .Ended) {
_webView!.goBack()
}
}
func handleGoForwardPan(sender: AnyObject) {
if (sender.state == .Ended) {
_webView!.goForward()
}
}
func handleSwipeFromTop(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animateAlongsideTransition({ context in
self._webView!.frame = CGRectMake(0, 0, size.width, size.height)
}, completion: nil)
}
}
And here are some screenshots to demonstrate the issue:
This is the view after it finished loading, working correctly:
This is the view after rotating the device to landscape:
And this is the scroll location after rotation:
使用 self.view = _webView 可以正确调整视图大小,但会忽略 Storyboard 上的所有视图(因为视图的内容正在被重写)。
如何解决这个问题(无需重写 self.view)?