'WKWebView align content to center (swift)
I have a Widget that previews PDF's and image files. My problem is that all small documents that take only part of the screen are aligned to the top of the page. How do I align them to center vertically?
Dart code:
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context!).appBarTheme.backgroundColor,
title: Text(title),
),
body: Center(
child: UiKitView(
viewType: "FileViewer",
onPlatformViewCreated: _onPlatformViewCreated,
creationParamsCodec: const StandardMessageCodec(),
),
),
);
AppDelegate.swift:
class FileReaderWKWebView : WKWebView {}
class FileReaderView: NSObject,FlutterPlatformView {
var _webView: FileReaderWKWebView?
init(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?, binaryMessenger messenger: FlutterBinaryMessenger) {
super.init()
let channel = FlutterMethodChannel.init(name: "wv.io/FileViewer_\(viewId)", binaryMessenger: messenger)
channel.setMethodCallHandler { (call, result) in
if call.method == "openFile" {
if isSupported(fileType: fileType(filePath: call.arguments as? String)){
self.openFile(filePath: call.arguments as! String)
result(true)
} else {
result(false)
}
return
}
if call.method == "canOpen" {
result(isSupported(fileType: fileType(filePath: call.arguments as? String)))
return
}
}
self._webView = FileReaderWKWebView.init(frame: frame)
}
func openFile(filePath:String) {
let url = URL.init(fileURLWithPath: filePath)
if #available(iOS 9.0, *) {
_webView?.loadFileURL(url, allowingReadAccessTo: url)
} else {
let request = URLRequest.init(url: url)
_webView?.load(request)
}
}
func view() -> UIView {
return _webView!
}
}
Solution 1:[1]
I don't have the full solution but I tried 2 things which can get you close and you can experiment from there.
Since this was tagged as Swift, I am giving pure swift solution.
First, here is basic WKWebview
class ViewController: UIViewController, WKNavigationDelegate
{
let webView = WKWebView()
override func viewDidAppear(_ animated: Bool)
{
super.viewDidAppear(animated)
var frame = view.bounds
frame.size = CGSize(width: frame.width, height: 150)
// webView.isHidden = true - unhide when you set final position
webView.frame = view.bounds
// important to know when PDF is loaded
webView.navigationDelegate = self
view.addSubview(webView)
loadPDF()
}
private func loadPDF()
{
if let pdfURL = Bundle.main.url(forResource: "test",
withExtension: "pdf",
subdirectory: nil,
localization: nil) {
do {
let data = try Data(contentsOf: pdfURL)
webView.load(data, mimeType: "application/pdf",
characterEncodingName:"",
baseURL: pdfURL.deletingLastPathComponent())
}
catch {
// catch errors here
}
}
}
Just doing this will give you same results as you have right now.
Next step I tried was to find the dimensions of the PDF after it had loaded and set the webview's scrollview content offset to center it:
// WKNavigationDelegate
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
{
// Delay because it takes some time to get the correct height after load
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { [weak self] in
self?.centerContentIfRequired()
}
}
private func centerContentIfRequired()
{
//
let pdfSize = webView.scrollView.contentSize
// Check if PDF height is less than 50% of screen height
// or any logic you want
if pdfSize.height < UIScreen.main.bounds.height / 2
{
let offsetY = (pdfSize.height / 2.0) - webView.center.y
webView.scrollView.setContentOffset(CGPoint(x: 0, y: offsetY), animated: false)
webView.isHidden = false
}
}
This gave me nice looking results:
But as soon as you touch it, it goes back to the top as before so this is drawback of this method.
You could play around more with this to see if you can get better results.
Then I thought, if I can get PDF size, I could resize the WebView itself to fit the PDF exactly and center the WebView on the screen.
// WKNavigationDelegate
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
{
// Delay because it takes some time to get the correct height after load
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { [weak self] in
self?.centerWebViewIfRequired()
}
}
private func centerWebViewIfRequired()
{
// Get PDF size
let pdfSize = webView.scrollView.contentSize
// Check if PDF height is less than 50% of screen height
// or any logic you want
if pdfSize.height < UIScreen.main.bounds.height / 2
{
var newFrame = webView.frame
newFrame.size = pdfSize
webView.frame = newFrame
webView.sizeToFit()
webView.center = view.center
webView.isHidden = false
}
}
This is still better than the first as content is centered, but doesn't look as clean as previous version because of additional grey area.
However, the experience is better and webview is centered. The issue is the PDF height is not returned accurately by the webview's scroll view in my opinion and hence we have the additional grey area.
My final conclusion is for you see if you can somehow find a way to get the PDF dimensions accurately, you will get the best results with the second version.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Shawn Frank |



