Add margin at top of webView in Swift IOS - ios

I am downloading files from server and showing in my ios device. File type can be any thing like image, pdf etc. and all loading up fine. Now the problem is, some part of file or image is hiding behind the title of page. I want to add margin at top of file after it loads up.
Code I have written to show file:
func openFile(file:String) {
let myBlog = file
let url = NSURL(string: myBlog)
let request = NSURLRequest(url: url! as URL)
webView.load(request as URLRequest)
self.view.addSubview(webView)
let pdfVC = UIViewController()
pdfVC.view.addSubview(webView)
pdfVC.title = "File"
self.navigationController?.pushViewController(pdfVC, animated: true)
self.navigationController!.navigationBar.tintColor = colors.whiteColor
}
I have created webView property within Class like:
var webView : WKWebView!
And inside viewDidLoad(), I have written:
webView = WKWebView(frame: self.view.frame)
webView.translatesAutoresizingMaskIntoConstraints = false
webView.isUserInteractionEnabled = true
webView.navigationDelegate = self
Result I am getting:
Here some part of image is behind the title. I have tried verious solutions given in link add margins in swift, but nothing is working.

My suggestion is to create instance of WKWebView in controller where you need to display it, in your case instance pdfVC
There is can be model, for example:
enum FileType {
case image(fileURL: URL)
case pdf(fileURL: URL)
}
Creating incase of FileViewController and assign fileType to it
func openFile(file:String) {
let pdfViewController = FileViewController()
pdfVC.fileType = FileType.pdf(fileURL: URL(string: "https://www.google.com")!) // example
pdfVC.title = "File"
navigationController?.pushViewController(pdfVC, animated: true)
}
And inside your VC where you need to display a file:
In this way, even if you do have navigationBar you won't have problem with navigationBar and topMargin
class FileViewController: UIViewController {
var fileType: FileType!
override func viewDidLoad() {
super.viewDidLoad()
var urlRequest: URLRequest!
switch fileType {
case .image(let url), .pdf(let url):
urlRequest = URLRequest(url: url)
#unknown default:
break
}
let webView = WKWebView(frame: view.frame)
webView.load(urlRequest)
self.view = webView
}
}
Hope this will help you!

use Bounds instead of Frame
webView = WKWebView(frame: self.view.Bounds)

Related

WKWebView -How to AutoPlay Video Without VideoID?

In my app I use WKWebView and the user can go to different websites like google, wikipedia, vimeo, etc. The issue is if the user decides to go to https://www.youtube.com, when the user taps a thumbnail to play it, it doesn't autoplay because I don't have the videoId (eg. "https://youtu.be/MpvshzR6tNk" + "&autoplay=1"), I just have the youtube website url
For example:
func loadRequest() {
let strThatUserEntered = "https://youtube.com"
let urlStr = "strThatUserEntered"
guard let url = URL(string: urlStr), let request = URLRequest(url: url) else { return }
wkWebView.load(request)
wkWebView.allowsBackForwardNavigationGestures = true
}
Now when the user selects a random thumbnail, the video loads, the youtube play button appears, and when it's pressed, I get An error occurred, please try again later (this video definitely works)
How can I enable autoplay on any selected youtube thumbnail, if I don't have the videoID?
code:
override func viewDidLoad()
super.viewDidLoad()
let webConfiguration = WKWebViewConfiguration()
webConfiguration.allowsInlineMediaPlayback = true
webConfiguration.mediaTypesRequiringUserActionForPlayback = []
wkWebView = WKWebView(frame: .zero, configuration: webConfiguration)
wkWebView.navigationDelegate = self
wkWebView.uiDelegate = self
// pin wkWebView anchors to screen
loadRequest()
}

How to create a iOS Webview App (HTML5) with Xcode?

I'm trying to load local html5 files to Xcode to create an ios App. I tried using a template and it uses both local and web based paths to create a very nice ios app in Xcode.
I need to learn about how to create a a webview app that has normal features and can load my local html5 webapps into Xcode for compiling an ios app.
I tried the following code, and it works alright when loading a url based html5 page.
import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate {
https://developer.apple.com/documentation/webkit/wkwebview
var webView: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let myURL = URL(string:"https://www.apple.com")
let myRequest = URLRequest(url: myURL!)
webView.load(myRequest)
}}
I need to change the URL to local file path. The above code page from apple documentation suggests that I use load(_: ) to load local html files. I'm not sure how to use this function. So, I tried code samples from alternate sources, and here's some part of the code I'm trying with for the Webview app.
import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate {
#IBOutlet var webView: WKWebView!
//var webView: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
guard let fileUrl = Bundle.main.path(forResource: "index", ofType: "html", inDirectory: "www-WebsiteContent") else { return; }
//let urlPath = Bundle.main.url(forResource: "input", withExtension: "txt")
if fileUrl != "" {
let url = URL(fileURLWithPath: fileUrl)
//let url = init(_: fileURLWithPath, path: "www-WebsiteContent/index.html")
webView.loadFileURL(url, allowingReadAccessTo : url)
let request = URLRequest(url: url)
webView.load(request)
}
//let myURL = URL(string:"file:///www-WebsiteContent/index.html")
//let myRequest = URLRequest(url: myURL!)
//webView.load(myRequest)
//webView.loadFileURL(URL: , webView.allowingReadAccessTo readAccessURL: URL)
}}
I'm using latest Xcode version on Macbook Air with latest Swift 5 version. There's a main storyboard with the webview object, and a viewcontroller.swift file.
The error is that when I run the project, it doesn't display the index.html file in the www-WebsiteContent folder. Maybe I wasn't able to connect the webview overlay to the viewcontroller.swift file properly.
Things I need to understand:
Can I run the above code and compile it as a complete ios app? Or would I need to edit AppDelegate or SceneDelegate files too? I've only edited the viewcontroller.swift file as a new project.
How can I resize the webview overlay to automatic width and height of the ios device? I have an html5 webapp files that I need to convert to an ios app. How can I create this webview so that it fits all the device types screen sizes? My html5 app fits perfectly when viewed in the device browser.

Playing sound pause when scrolling WKWebView

I have a simple WKWebView controller in my application that loads a local HTML file. HTML file including following code...
<audio autoplay="true" controls>
<source src="./audio/sound.mp3" type="audio/mpeg">
Your browser does not support the audio tag.
</audio>
Everything works fine, but when the user scrolls the webview, the sound stops, when the scrolling ends, the playback continues.
override func viewDidLoad() {
super.viewDidLoad()
let htmlPath = Bundle.main.path(forResource: "main", ofType: "htm", inDirectory: "level")
let url = URL(fileURLWithPath: htmlPath!)
let request = URLRequest(url: url)
webView.load(request)
}
Trying load remote file, but problem is same:
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://www.computerhope.com/jargon/h/html-audio-tag.htm")!
let request = URLRequest(url: url)
webView.load(request)
}
iOS version: 12.1
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://www.computerhope.com/jargon/h/html-audio-tag.htm")!
myWebKit.load(URLRequest(url: url))
myWebKit.allowsBackForwardNavigationGestures = true
// Do any additional setup after loading the view.
}
I tried this code.. its working fine for me.. audio is still playing while scrolling the page
myWebKit.allowsBackForwardNavigationGestures = true
try this

iOS PDFKit textfield form input

I am currently developing a iOS app which can download PDF(Have form on it) from server to iPad, then user can fill in the form on the iPad.
The problem is we need to support chinese on the field input.
Here is the field.
When I use "Quick" input method to type any character, it repeat 3 times.
When I type one more time, it repeat again.
Do anyone have issues with typing Chinese in textfield using PDFKit on iOS?
Update, Add code work
For the server-side, just a endpoint can download pdf, the pdf already added textfield on it.
On client-side, pdf is downloaded in viewDidLoad() and set into pdfView as following code.
override func viewDidLoad() {
super.viewDidLoad()
if let code = self.code {
let url = URL(string : API.pdf + "/" + code)
let loading = self.showLoading()
var request = URLRequest(url: url!)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request, completionHandler: { (responseData: Data?, response: URLResponse?, error: Error?) in
DispatchQueue.main.async {
self.pdfView.document = PDFDocument(data : responseData!)
self.pdfView.scaleFactor = 1
self.pdfView.backgroundColor = UIColor.lightGray
self.pdfView.autoScales = true
loading.dismiss(animated: true, completion: nil)
}
})
task.resume()
}
}
In story board, it is just a UIView and set custom class as PDFView
Updated 2
After that, i do a simple testing.
I create a simple testing controller and load pdf with just a simple textfield annotation. Result is same.
import UIKit
import PDFKit
class PDFTestViewController : ViewController {
#IBOutlet weak var pdfView: PDFView!
override func viewDidLoad() {
super.viewDidLoad()
if let url = Bundle.main.url(forResource: "4547315264964", withExtension: "pdf"),
let doc = PDFDocument(url: url){
self.pdfView.document = doc
self.pdfView.scaleFactor = 1
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}

Change string in other class (without making it global) in swift

I would like to modify a string in another class. This class will then use the variable in a function.
Here is what I've tried so far. I always get an error when unwrapping it: fatal error: unexpectedly found nil while unwrapping an Optional value. Does anyone have an idea how to change the urlString (preferably without making it global)? I couldn't find solutions for swift which also involved functions on stackoverflow... If you think I will have to make it global, please let me know!
In class #1
let videoUrl = "https:...sometestvideo.mov"
videoPlayerView.urlString = videoUrl
In class #2
var urlString : String?
//setup video player
func setupPlayerView() {
print(urlString)
//URL needed here
if let videoURL = NSURL(string: urlString!){ //here the error occurs
I would like to add that it is very important that the function is called asap in the second class. Therefore I didn't use setupPlayerView(_urlString)...
Accordingly it currently looks like this (class 2, a UIView):
override init(frame: CGRect){
super.init(frame: frame)
//function below this override init
setupPlayerView()
EDIT:
First of all, thank you for your solution! Nonetheless, one little problem remains (and I thought calling the function immediately would solve it... quite new to swift): namely the video player (which is set up using this function) is now above all the other subviews (one can only see the video covering the entire screen) although the opposite is desired (video using entire screen but subviews cover some parts). I will provide more code below regarding the addition of other subviews (all of these are closures) and the function setting up the view. Is there a way I can keep the videoplayer below all the other subviews (even if it needs to be loaded from a server first)? What would you suggest me to do?
Code below incorporates code from the first answer, but does not necessarily have to start from there
Class 2
override init(frame: CGRect){
super.init(frame: frame)
setupPlayerView()
//add subview with controls (e.g. spinner)
controlsContainerView.frame = frame
addSubview(controlsContainerView)
//add to subview and center spinner in subview
controlsContainerView.addSubview(activityIndicatorView)
activityIndicatorView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
activityIndicatorView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
//add various subviews
controlsContainerView.addSubview(whiteDummyView)
controlsContainerView.addSubview(userProfilePicture)
//... add further subviews
//enable interaction
controlsContainerView.isUserInteractionEnabled = true
//... set to true for other subviews as well
//function below this override init
defInteractions()
//backgorund color of player
backgroundColor = .black
}
//create controls container view (a closure, like the (most of the) other subviews)
let controlsContainerView: UIView = {
//set properties of controls container view
let controlView = UIView()
controlView.backgroundColor = UIColor(white: 0, alpha: 1)
return controlView
}()
function setupPlayerView()
//setup video player
func setupPlayerView() {
//check URL if can be converted to NSURL
if let urlString = self.urlString, let videoURL = NSURL(string: urlString){
print(urlString)
//player's video
if self.player == nil {
player = AVPlayer(url: videoURL as URL)
}
//add sub-layer
let playerLayer = AVPlayerLayer(player: player)
self.controlsContainerView.layer.addSublayer(playerLayer)
playerLayer.frame = self.frame
//when are frames actually rendered (when is video loaded)
player?.addObserver(self, forKeyPath: "currentItem.loadedTimeRanges", options: .new, context: nil)
//loop through video
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem, queue: nil, using: { (_) in
DispatchQueue.main.async {
self.player?.seek(to: kCMTimeZero)
self.player?.play()
}
})
}
}
Without too much context about the relationship between your classes, looks like a potentially good solution is to use a property observer pattern.
class Class2 {
var urlString: String? {
didSet {
setupPlayerView()
}
}
override init(frame: CGRect){
super.init(frame: frame)
setupPlayerView()
}
func setupPlayerView() {
if let urlString = self.urlString, let videoURL = NSURL(string: urlString) {
// do stuff here
}
}
}
While navigating to second view controller.
let viewController2 = ViewController2() //viewController2 == class2
viewController2.urlString = videoUrl // anything you want to pass to class2.
navigationController?.pushViewController(viewController2, animated: true)
In your class 2:
var urlString: String = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
print(urlString) // use it
setupPlayerView()
}
Your func:
func setupPlayerView() {
//check URL if can be converted to NSURL
if NSURL(string: urlString) != nil{
print(urlString)
}
}

Resources