WKWebView added as Subview is not resized on rotation in Swift
Solution 1
I managed to solve the problem by using this line of code:
self._webView!.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
:)
Solution 2
swift 3 version:
webView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
Solution 3
I'm posting an answer for Objective-C, just in case if someone comes here looking for it
[self.webView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
Related videos on Youtube
PastaCoder
Updated on September 27, 2022Comments
-
PastaCoder over 1 year
I'm working on adding a new reading view to my browser app. It is another view controller, that only includes a WKWebView added as a subview with a button (and gesture) to close the view. Everything works great, but when I rotate the device, the subview isn't resized, so I have one half of the screen empty.
The WKWebView in the Reading View gets the URL of the main View Controller with a segue performed after the user taps a button on the main View Controller and that URL is stored as webpageURL.
Here is the code I used:
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:
Using self.view = _webView makes the view resize correctly, but ignores all the views on the Storyboard (since the View's contents are being rewritten).
How can I fix this issue (without rewriting self.view)?
-
Joel almost 9 yearsI'd up vote this more than once if I could! Thanks!
-
Mike Cole over 8 yearsNew syntax would be
webView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
. -
tech4242 almost 8 yearsThis is a life saver! Using NSLayoutConstraints with WKWebView was not the best experience to say the least
-
Oliver Zhang over 7 yearsThanks a lot! This is fantastic!
-
computingfreak about 7 yearsmind the case, webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
-
Itachi over 6 yearsWhat's the replacement of layout constraints?
-
CupawnTae about 5 yearsor of course
self.webView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
-
Gleno almost 2 yearsNewest syntax would be: self.webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]