WKWebView - Margin Top - swift

I'm starting swift.
Code is a webview without superior navigation, constrain moves the webview from the top leaving an upper margin.
see the image
Image Result
My code
import UIKit
import WebKit
class ViewController: UIViewController,WKNavigationDelegate, WKUIDelegate {
lazy var webView: WKWebView = {
let webConfiguration = WKWebViewConfiguration()
let webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
webView.navigationDelegate = self
webView.translatesAutoresizingMaskIntoConstraints = false
return webView
}()
func setupUI() {
self.view.backgroundColor = .red
self.view.addSubview(webView)
NSLayoutConstraint.activate([
webView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
webView.leftAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leftAnchor),
webView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),
webView.rightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.rightAnchor)
])
}
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
let myURL = URL(string: "https://www.google.com.br/")
let myRequest = URLRequest(url: myURL!,cachePolicy: NSURLRequest.CachePolicy.useProtocolCachePolicy,timeoutInterval: 10.0)
webView.load(myRequest)
}
}

Solved. Just add:
self.navigationController? .isNavigationBarHidden = true

Related

Printing from WKWebView in Swift ignores background

I try to print html code to a pdf with the following code:
class PDFPrinter: NSObject, WKNavigationDelegate {
static var shared = PDFPrinter()
let webView = WKWebView()
private var saveURL: URL!
private var completion: () -> () = {}
override init() {
super.init()
self.webView.navigationDelegate = self
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
let printInfo = NSPrintInfo(dictionary: [
.paperSize: CGSize(width: 595.28, height: 841.89),
.jobDisposition: NSPrintInfo.JobDisposition.save,
.jobSavingURL: self.saveURL!,
])
printInfo.horizontalPagination = .automatic
printInfo.verticalPagination = .automatic
let margin = 20.0
printInfo.leftMargin = margin
printInfo.topMargin = margin
printInfo.rightMargin = margin
printInfo.bottomMargin = margin
let pro = self.webView.printOperation(with: printInfo)
pro.showsPrintPanel = false
pro.showsProgressPanel = false
let selector = #selector(self.printOperationDidRun(printOperation: success: contextInfo:))
pro.runModal(for: NSWindow(), delegate: self, didRun: selector, contextInfo: nil)
}
func printHTML(htmlString: String, saveURL: URL, completion: #escaping () -> ()) {
self.saveURL = saveURL
self.completion = completion
webView.loadHTMLString(htmlString, baseURL: nil)
}
#objc func printOperationDidRun( printOperation: NSPrintOperation,
success: Bool,
contextInfo: UnsafeMutableRawPointer?){
self.completion()
}
}
This works except of one thing: The background of the html is completely ignored, my pdf is always completely white. I could not find any setting in WKWebView, NSPrintInfo or NSPrintOperation how to change that. Any ideas?

WKWebView view not resizable

I'm creating a macOS Swift app, I'm new to Swift. I'm trying to make the view resizable like web browsers (Chrome, Firefox, etc.), however my code doesn't seem to work, and I didn't find anything useful about WKWebView resizing.
Here's my code for the ViewController:
import Cocoa
import WebKit
class ViewController: NSViewController, WKUIDelegate
{
var webView: WKWebView!
override func loadView()
{
let webConfiguration = WKWebViewConfiguration ();
webConfiguration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs");
webView = WKWebView (frame: CGRect(x:0, y:0, width:1920, height:1080), configuration:webConfiguration);
webView.uiDelegate = self;
self.view = webView;
}
override func viewDidLoad() {
super.viewDidLoad()
let webView = WKWebView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.webView.frame.size.height))
self.view.addSubview(webView)
let url = URL(string: "https://www.google.com/")
webView.load(URLRequest(url: url!))
}
}
Results:
Okay so I figured out how to fix the issue with Willeke's recommendation:
Replace this:
let webView = WKWebView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.webView.frame.size.height))
self.view.addSubview(webView)
let url = URL(string: "https://www.google.com/")
webView.load(URLRequest(url: url!))
With this:
if let url = URL(string: "https://www.roblox.com/") {
let request = URLRequest(url: url)
webView.load(request)
}

Black screen on ARView

I am trying to programmatically instantiate an ARView. This is my code for the View Controller
import Foundation
import UIKit
import RealityKit
class ARViewController: UIViewController {
var arView: ARView = {
let arview = ARView()
arview.cameraMode = .ar
arview.automaticallyConfigureSession = true
arview.translatesAutoresizingMaskIntoConstraints = false
return arview
}()
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
setupUIConstraints()
}
func setupUI() {
view.addSubview(arView)
// Load the "Cupcake" scene from the "Experience" Reality File
let boxAnchor = try! Experience.loadBox()
// Add the box anchor to the scene
arView.scene.anchors.append(boxAnchor)
}
func setupUIConstraints() {
view.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
view.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
view.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
view.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
}
}
The app will appropriately ask me for Camera permissions, but even after accepting, the 'view' is just a black screen. I am on an iPhone XS, and have imported arkit into my info.plist. Any help would be much appreciated.
In setupUIConstraints you're setting the constraints for the ARViewController.view to its own constraints, rather than the ARView.
Change to the ARView and you should be good!

"Init(URL:)" has been renamed to "init(url:)" - swift 3 wkwebview error

First time using webkit alongside swift 3, and I keep getting this error regarding a web view load request. Why is Xcode announcing the renaming but maintaining the error?
var webView: WKWebView!
var websites = ["apple.com", "hackingwithswift.com"]
override func loadView() {
webView = WKWebView()
webView.navigationDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL(string: "https://" + websites[0])!
webView.load(NSURLRequest(URL: url as URL) as URLRequest)
webView.allowsBackForwardNavigationGestures = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
As suggested by #LeoDabus, here's the code
class Controller: UIViewController {
var webView: WKWebView!
var websites = ["apple.com", "hackingwithswift.com"]
override func loadView() {
webView = WKWebView()
webView.navigationDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://" + websites[0])!
webView.load(URLRequest(url: url) as URLRequest)
webView.allowsBackForwardNavigationGestures = true
}
}
I had the same issue which i solved using following lines of code
let url = NSURL (string: "http://www.sourcefreeze.com")
let requestObj = NSURLRequest(url: url! as URL)
webview.loadRequest(requestObj as URLRequest)

UIWebView dynamic content size

I've been looking around and wasnt able to see any swift related ways to do this. I'm trying to get my UIWebViews height to be dynamic. I have a UIWebView that loads data using the loadHtmlString function.The thing is that I am loading the data from an sqlite database, each time I load a different string with different length and naturally the web view obtains different height.
Now I need to know how to make the UIWebView that exact height in order to load my next content right under the webView. This is what I have so far
var jobSkillView = UIWebView(frame: CGRectMake(-5, 480.0, screenWidth, 300.0))
jobSkillView.loadHTMLString("<html><body p style='font-family:arial;font-size:16px;'>" + jobSkills + "</body></html>", baseURL: nil)
jobSkillView.stringByEvaluatingJavaScriptFromString("document.body.innerHTML")
jobSkillView.scrollView.scrollEnabled = true
jobSkillView.scrollView.bounces = true
jobSkillView.sizeToFit()
border.addSubview(jobSkillView)
I found something like this on SO but not sure how to link it to the UIWebView's frame:
func webViewDidFinishLoad(jobSkillView : UIWebView){
// Change the height dynamically of the UIWebView to match the html content
var jobSkillViewFrame: CGRect = jobSkillView.frame
jobSkillViewFrame.size.height = 1
jobSkillView.frame = jobSkillViewFrame
var fittingSize: CGSize = (jobSkillView.sizeThatFits(CGSizeZero))
jobSkillViewFrame.size = fittingSize
// webViewFrame.size.width = 276; Making sure that the webView doesn't get wider than 276 px
jobSkillView.frame = jobSkillViewFrame
var jobSkillViewHeight = jobSkillView.frame.size.height
}
This post has been updated for Swift 5 & WKWebView
So this is a really great function you wrote there, OP!
Here is just a shorter, more elegant version of your code:
// make sure to declare the delegate when creating your webView (add UIWebViewDelegate to class declaration as well)
myWebView.delegate = self
func webViewDidFinishLoad(webView: UIWebView) {
webView.frame.size.height = 1
webView.frame.size = webView.sizeThatFits(CGSize.zero)
}
Migrating to WKWebView
1) import WebKit
2) make your ViewController inherit from WKNavigationDelegate
3) hook up the WKWebView’s delegate: webView.navigationDelegate = self
4) implement the following protocol function:
webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
After migrating from UIWebView to WKWebView, above approach doesn’t seem to work anymore.
What you can do instead, is change the line with webView.sizeThatFits(CGSize.zero) to:
webView.frame.size = webView.scrollView.contentSize
The full code for WKWebView would then be:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.frame.size.height = 1
webView.frame.size = webView.scrollView.contentSize
}
this only worked for me
func webViewDidFinishLoad(_ webView: UIWebView) {
webView.frame.size.height = 1
webView.frame.size = webView.sizeThatFits(.zero)
webView.scrollView.isScrollEnabled=false;
myWebViewHeightConstraint.constant = webView.scrollView.contentSize.height
webView.scalesPageToFit = true
}
make sure you've created an outlet for myWebViewHeightConstraint
Here is my custom class to work with custom UIWebViews, it has everything in it to get the correct scrollview content height, set UIWebView height and create a custom height constraint to get autolayout working. It also loads some custom CSS styling...
class CustomUIWebView: UIWebView, UIWebViewDelegate {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.scrollView.scrollEnabled = false
self.scrollView.bounces = false
self.delegate = self
}
override init(frame: CGRect) {
super.init(frame: frame)
self.scrollView.scrollEnabled = false
self.scrollView.bounces = false
self.delegate = self
}
override func loadHTMLString(string: String!, baseURL: NSURL!) {
var cssURL:String = NSBundle.mainBundle().pathForResource("webview", ofType: "css")!
var s:String = "<html><head><title></title><meta name=\"viewport\" content=\"initial-scale=1, user-scalable=no, width=device-width\" /><link rel=\"stylesheet\" href=\"./webview.css\" ></link></head><body>"+string+"</body></html>";
var url:NSURL
if baseURL == nil {
url = NSBundle.mainBundle().bundleURL
} else {
url = baseURL
}
super.loadHTMLString(s, baseURL: url)
}
func webViewDidFinishLoad(webView: UIWebView) {
self.webViewResizeToContent(webView)
}
func webViewResizeToContent(webView: UIWebView) {
webView.layoutSubviews()
// Set to smallest rect value
var frame:CGRect = webView.frame
frame.size.height = 1.0
webView.frame = frame
var height:CGFloat = webView.scrollView.contentSize.height
println("UIWebView.height: \(height)")
webView.setHeight(height: height)
let heightConstraint = NSLayoutConstraint(item: webView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.Height, multiplier: 1.0, constant: height)
webView.addConstraint(heightConstraint)
// Set layout flag
webView.window?.setNeedsUpdateConstraints()
webView.window?.setNeedsLayout()
}
}
I had problem with:
let height = webView.scrollView.contentSize.height
Sometimes my web view height simply didn't calculacte and stayed on default value.
So finally I manage to find better solution that works fine, just replace that line code with:
let height = webView.stringByEvaluatingJavaScript(from: "document.body.scrollHeight")
This is mine final complete code:
func webViewDidFinishLoad(_ webView: UIWebView) {
//webview height
webView.frame.size.height = 1
webView.frame.size = webView.sizeThatFits(.zero)
webView.scrollView.isScrollEnabled = false
let height = webView.stringByEvaluatingJavaScript(from: "document.body.scrollHeight")
if let height = height {
if let heightInt = Int(height) {
let heightFloat = Float(heightInt)
webViewHeightConstraint.constant = CGFloat(heightFloat)
}
}
webView.scalesPageToFit = true
}
I'm using HTML string in my load and have to use the following method in Webview delegate:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript("document.documentElement.scrollHeight", completionHandler: { (height, error) in
self.webviewHeightConstraint?.constant = height as! CGFloat
})
}
and the full code:
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
#IBOutlet weak var webviewHeightConstraint: NSLayoutConstraint!
#IBOutlet weak var webview: WKWebView!
var observing = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
webview.navigationDelegate = self
webview.scrollView.isScrollEnabled = false
self.webview.loadHTMLString("""
<html>
<head>
<style>
ul {
list-style: none;
}
ul li::before {
content: "\\2022";
color: red;
font-weight: bold;
display: inline-block;
width: 1em;
margin-left: -1em;
}
</style>
</head>
<body>
<h2>Change Bullet Color of List Items</h2>
<ul>
<li>Adele</li>
<li>Agnes</li>
<li>Billy</li>
<li>Bob</li>
<li>Bob</li>
<li>Bob</li>
<li>Bob</li>
<li>Bob</li>
<li>Bob</li>
<li>Bob</li>
<li>Bob</li>
<li>Bob</li>
<li>Bob</li>
<li>Bob</li>
</ul>
</body>
</html>
""", baseURL: nil)
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript("document.documentElement.scrollHeight", completionHandler: { (height, error) in
self.webviewHeightConstraint?.constant = height as! CGFloat
})
}
}
Okay I figured out what I was doing wrong so now I know how to call this function. First of all I was supposed to call a UIWebViewDelegate in my class. Then set my var jobSkillView to (jobSkillView.delegate = self). Now this is where I made my major mistake. In my code I had a if else statement that I was throwing my func webViewDidLoad in. I was supposed to put it out of that statement and into the actual class to override my frame for the UIWebView. Speaking of frame **** DONT FORGET TO SET YOUR FRAME HEIGHT TO 1. Then and only then this function will work for your UIWebView. After that you should have a fully functional based height for your UIWebView for Swift.
Use the following code to make your UIWebView height dynamic in Swift 3.x
func webViewDidFinishLoad(_ webView: UIWebView) {
let height = webView.scrollView.contentSize.height
var wRect = webView.frame
wRect.size.height = height
webView.frame = wRect
}
you can use this class for makking webview size to fit for swift 3 and swift 4
//
// RSWebView.swift
// CustumWebViewDemo
//
// Created by Ruchin Somal on 01/01/18.
// Copyright © 2018 Ruchin Somal. All rights reserved.
//
import UIKit
class RSWebView: UIWebView, UIWebViewDelegate {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.scrollView.isScrollEnabled = false
self.scrollView.bounces = false
self.delegate = self
}
override init(frame: CGRect) {
super.init(frame: frame)
self.scrollView.isScrollEnabled = false
self.scrollView.bounces = false
self.delegate = self
}
override func loadHTMLString(_ string: String?, baseURL: URL?) {
let s:String = "<html><head><title></title><meta name=\"viewport\" content=\"initial-scale=1, user-scalable=no, width=device-width\" /><link rel=\"stylesheet\" href=\"./webview.css\" ></link></head><body>"+string!+"</body></html>";
var url:URL
if baseURL == nil {
url = Bundle.main.bundleURL
} else {
url = baseURL!
}
super.loadHTMLString(s, baseURL: url)
}
func webViewDidFinishLoad(_ webView: UIWebView) {
self.webViewResizeToContent(webView: webView)
}
func webViewResizeToContent(webView: UIWebView) {
webView.layoutSubviews()
// Set to initial value of webview
var frame:CGRect = webView.frame
frame.size.height = 1.0
webView.frame = frame
// Calculated height of webview
let wvheight: CGFloat = webView.scrollView.contentSize.height
print("UIWebView.height: \(wvheight)")
var wvRect = webView.frame
wvRect.size.height = wvheight
webView.frame = wvRect
let heightConstraint = NSLayoutConstraint(item: webView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.height, multiplier: 1.0, constant: wvheight)
webView.addConstraint(heightConstraint)
webView.window?.setNeedsUpdateConstraints()
webView.window?.setNeedsLayout()
}
}
When font change at that time change Webview height to 1 than get proper offsetHeight for Webview
webView1.frame.size.height = 1
Try with
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.frame.size.height = 1
webView.frame.size = webView.sizeThatFits(.zero)
webView.scrollView.isScrollEnabled = false
let height = webView.scrollView.contentSize.height
}