Je travaille sur l'ajout d'une nouvelle lecture à l'application de mon navigateur. C'est un autre contrôleur de vue, qui inclut uniquement un WKWebView ajouté en tant que sous-vue avec un bouton (et un geste) pour fermer la vue. Tout fonctionne très bien, mais lorsque je fais pivoter le périphérique, la sous-vue n'est pas redimensionnée. Il reste donc une moitié de l'écran vide.
Le WKWebView dans l'affichage de lecture obtient l'URL du contrôleur de vue principal avec une division effectuée après que l'utilisateur a appuyé sur un bouton du contrôleur de vue principal et que cette URL est stockée en tant que page webURL.
Voici le code que j'ai utilisé:
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)
}
}
Et voici quelques captures d'écran pour illustrer le problème: Voici la vue, une fois le chargement terminé, qui fonctionne correctement:
Voici la vue après la rotation de l'appareil en mode paysage:
Et voici le lieu de défilement après rotation:
Si vous utilisez self.view = _webView, la vue est redimensionnée correctement mais ignore toutes les vues du scénarimage (car le contenu de la vue est en cours de réécriture).
Comment puis-je résoudre ce problème (sans réécrire self.view)?
J'ai réussi à résoudre le problème en utilisant cette ligne de code:
self._webView!.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
:)
Swift 3 version:
webView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
Je poste une réponse pour Objective-C, juste au cas où quelqu'un viendrait la chercher
[self.webView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
En fait, comme WKWebView ne peut être ajouté que par programme, l'indicateur Masque de redimensionnement automatique en contraintes est activé par défaut (lors de l'ajout de composants et de contraintes dans Interface Builder, il est généralement désactivé pour vous). Je pense que la bonne solution serait:
webView?.translatesAutoresizingMaskIntoConstraints = false
après avoir ajouté les contraintes/ancres.