I am trying to load a pdf using web view using swift. It can load only one page of the pdf, cannot scroll down more than one page. What can i do?
import UIKit
class ViewController: UIViewController,UIWebViewDelegate {
#IBOutlet var webViews: UIWebView!
var path = ""
override func viewDidLoad() {
super.viewDidLoad()
path = NSBundle.mainBundle().pathForResource("ibook", ofType: "pdf")!
let url = NSURL.fileURLWithPath(path)
/*webViews.scalesPageToFit = true
webViews.scrollView.scrollEnabled = true
webViews.userInteractionEnabled = true*/
webViews.delegate = self
self.webViews.loadRequest(NSURLRequest(URL: url!
))
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func webViewDidStartLoad(webView : UIWebView) {
//UIApplication.sharedApplication().networkActivityIndicatorVisible = true
println("webViewDidStartLoad")
}
func webViewDidFinishLoad(webView : UIWebView) {
//UIApplication.sharedApplication().networkActivityIndicatorVisible = [enter image description here][1]false
webViews.scalesPageToFit = true
webViews.scrollView.scrollEnabled = true
webViews.userInteractionEnabled = true
println("webViewDidFinishLoad")
}
}
I've bumped into the similar problem while trying to display external pdf (not the bundled one), but I suppose you can use the same fix.
In your webViewDidFinishLoad, check if the url is actually a pdf one. Because in my case I know what I'm expecting, I used simple dumb checking. If url links to a pdf, you need to reload the web view to show it correctly and hence be able to scroll.
Here is a bit simplified code in objective C. It should be quite similar in Swift. Try something like this:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
static BOOL isPdfReloaded = NO;
if (!isPdfReloaded && [webView.request.URL.absoluteString containsString:#".pdf"])
{
[webView reload];
isPdfReloaded = YES;
}
else
{
isPdfReloaded = NO;
}
}
The Best solution is to migrate from UIWebView to WkWebView
Related
There is a default Core Graphics method that tells the current active PDF page number.
Is there any way to get the current active page number as showing by the page indicator?
And also is there any way to hide the the page indicator?
Answer in Objective-C would be appreciated.
It is easy to get page number in PDFKit. Please find the below code snippet.
print(pdfDocument!.index(for: pdfView.currentPage!))
Swift 5.1
A Simple Solution
#IBOutlet var pageNumber: NSTextField!
let curPg = self.thePDFView.currentPage?.pageRef?.pageNumber
pageNumber.stringValue = "Page \(String(describing: curPg!))"
This is an old question and the answer should be in Objc but I had to do a quite similar approach in Swift and here's my solution.
First I created a outlet for container, a label for current page and the another label for current page;
#IBOutlet weak var pageInfoContainer: UIView!
#IBOutlet weak var currentPageLabel: UILabel!
#IBOutlet weak var totalPagesLabel: UILabel!
Also a timer that will explain below;
private var timer: Timer?
To get the current page a soon as it changes you need to add an observer;
NotificationCenter.default.addObserver(self, selector: #selector(handlePageChange), name: Notification.Name.PDFViewPageChanged, object: nil)
Do not forget to remove the observer in viewWillDisappear!
Now that you have everything in place let's apply some logic!
Here's my setup for pdfView;
private func setupPdfView() {
if let pdf: PDFDocument = pdfDocument {
pdfView.autoScales = true
pdfView.backgroundColor = .clear
pdfView.document = pdf
pdfView.usePageViewController(true, withViewOptions: nil)
}
if let totalPages: Int = pdfView.document?.pageCount {
totalPagesLabel.text = String(totalPages)
}
}
The method that will handle the pageChange through the observer;
#objc func handlePageChange() {
if let currentPage: PDFPage = pdfView.currentPage, let pageIndex: Int = pdfView.document?.index(for: currentPage) {
UIView.animate(withDuration: 0.5, animations: {
self.pageInfoContainer.alpha = 1
}) { (finished) in
if finished {
self.startTimer()
}
}
currentPageLabel.text = String(pageIndex + 1)
}
}
And finally the timer and method;
private func startTimer() {
timer?.invalidate()
timer = Timer.scheduledTimer(timeInterval: 2.0, target: self, selector: #selector(whenTimerEnds), userInfo: nil, repeats: false)
}
#objc func whenTimerEnds() {
UIView.animate(withDuration: 1) {
self.pageInfoContainer.alpha = 0
}
}
Bear in mind that the timer is being used as a "candy" and is completely optional, this will remove the counter after X seconds on the same page
Stay safe!
Objective C
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((CFURLRef)[NSURL fileURLWithPath:#"pdf path"]);
int pageCount = CGPDFDocumentGetNumberOfPages(pdf);
CGPDFDocumentRelease(pdf);
Set delegate
self.webView.delegate = self;
Implement webViewDidFinishLoad method and you will get page count as follow...
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSInteger pageCount = webView.pageCount;
//OR
NSInteger count_horizontal = webView.scrollView.contentSize.width / webView.scrollView.frame.size.width;
NSInteger count_verticel = webView.scrollView.contentSize.height / webView.scrollView.frame.size.height;
}
Swift version for other
Get number of pages from pdf file.
guard var pdf = CGPDFDocument(URL(fileURLWithPath: "pdf path") as CFURL) else {
print("Not able to load pdf file.")
return
}
let pageCount = CGPDFDocumentGetNumberOfPages(pdf);
Display pdf in web view and set its delegate
self.webView.delegate = self;
Implement webViewDidFinishLoad method and you will get page count as follow...
extension YourViewController: UIWebViewDelegate {
func webViewDidFinishLoad(_ webView: UIWebView) {
let count = webView.pageCount
// OR
// when horizontal paging is required
let count_horizontal = webView.scrollView.contentSize.width / webView.scrollView.frame.size.width;
// when vertical paging is required
let count_vertical = webView.scrollView.contentSize.height / webView.scrollView.frame.size.height;
}
}
Scenario:
Creating a social network app type application, when user type the web address or valid url in the text area my app should identify the valid url,then I have to do the following tasks,
1) If it is a valid web url then automatically show the preview of the web contents in the preview section.
2) Share button should not be enabled until the preview is fully loaded, if not there are some chances that URL alone may be posted instead of the web contents.
What I have tried?
Created a Text view and a preview WebUI view, I used following code to identify the valid URL, if valid url then I am showing the web view and loading the web page.
Code what I tried:
class CommentsViewController: UIViewController {
#IBOutlet weak var comments: UITextField!
#IBOutlet weak var preview: UIWebView!
#IBOutlet weak var btnShare: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
preview.isHidden = true
btnShare.isEnabled = false
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func valueModified(_ sender: Any) {
//Load web preview only after Check for Valid Web URL
if verifyUrl(urlString: comments.text) == true {
preview.isHidden = false
preview.loadRequest(URLRequest(url: URL(string: comments.text!)!))
btnShare.isEnabled = true
}
}
//Check for Valid Web URL
func verifyUrl (urlString: String?) -> Bool {
//Check for nil
if let urlString = urlString {
// create NSURL instance
if let url = NSURL(string: urlString) {
// check if your application can open the NSURL instance
return UIApplication.shared.canOpenURL(url as URL)
}
}
return false
}
}
What I need exactly?
I do not want to load the web page, I have to load the preview of the page.
Share button should be hidden until the preview is fully loaded.
Screen shot of my code output:
Screen shot of what I am expecting:
I'm trying to check if the URL has changed in the webView. For example if I were to initially load a page like a Wordpress Sign In page, and I wanted to know when it changed and got redirected to the login page. I tried using this resource enter link description here but the answer seems to be incomplete and does not work.
func validateUrl (stringURL : NSString) -> Bool {
var urlRegEx = "((https|http)://)((\\w|-)+)(([.]|[/])((\\w|-)+))+"
let predicate = NSPredicate(format:"SELF MATCHES %#", argumentArray:[urlRegEx])
var urlTest = NSPredicate.predicateWithSubstitutionVariables(predicate)
return predicate.evaluateWithObject(stringURL)
}
urlTest is never called so i'm not sure the purpose of it.
if (validateUrl(stringURL: "http://google.com")) {
//will return true
print("Do Stuff");
}
else {
print("OTHER STUFf")
//If it is false then do stuff here.
}
And then to call this function
func webView(WebViewNews: UIWebView!, shouldStartLoadWithRequest request: NSURLRequest!, navigationType: UIWebViewNavigationType) -> Bool {
if (validateUrl(request.URL().absoluteString())) {
//if will return true
print("Do Stuff");
}
}
I added a return function at the end of my code, but the example does not include a return. I have very little experience in Webview, so any advice or help would be appreciated.
Use the webViewDidFinishLoad function of the UIWebViewDelegate to get the current URL loaded in your webview. Everytime the webview loads a URL the function webViewDidFinishLoad is called.
class YourClass: UIViewController, UIWebViewDelegate {
let initialURL = URL(string: "https://www.google.com.pe/")
#IBOutlet weak var webView:UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
webView.loadRequest( URLRequest(url: initialURL) )
}
func webViewDidFinishLoad(_ webView: UIWebView) {
if webView.request != URLRequest(url: initialURL!) {
//DO YOUR STUFF HERE
}
}
}
I am attempting to load a lunch menu PDF into a web view for a high school app that I am updating. Currently, it can load a PDF into the web view and display it just fine, but I want to speed up the monthly update process by having my app receive the link through Parse (Which I can update much quicker than updating the link in the app itself with Apple's 7 day review period), and then load the PDF. Currently, with what I have put together, my app will not load the PDF. Here's the entire view:
import UIKit
class AlaCarte_ViewController: UIViewController {
#IBOutlet weak var webviewAlaCarte: UIWebView!
var urlpath = String()
func loadAddressUrl(){
let requestURL = NSURL (string:urlpath)
let request = NSURLRequest(URL: requestURL!)
webviewAlaCarte.loadRequest(request)
alaCarteUpdate()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
clearPDFBackground(self.webviewAlaCarte)
}
func clearPDFBackground(webView: UIWebView) {
var view :UIView?
view = webView as UIView
while view != nil {
if NSStringFromClass(view?.dynamicType) == "UIWebPDFView" {
view?.backgroundColor = UIColor.clearColor()
}
view = view?.subviews.first as! UIView?
}
}
func alaCarteUpdate() {
var query = PFQuery(className: "AlaCarte")
query.getObjectInBackgroundWithId("rT7MpEFySU") {(AlaCarte: PFObject!, error: NSError!)-> Void in
if error == nil && AlaCarte != nil {
println(AlaCarte)
} else {
println(error)
}
let AlaCarteLink = AlaCarte["webaddress"] as! String
self.urlpath = AlaCarteLink
}
}
override func viewDidLoad() {
super.viewDidLoad()
loadAddressUrl()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
The link is stored in my Parse app as "webaddress" and does not contain end quotations. Adding them does not help. Any ideas?
It looks to me like you're not telling the web view to load the URL once it's retrieved from Parse.
Try adding the following lines after self.urlpath = AlaCarteLink in alaCarteUpdate().
let requestURL = NSURL (string:self.urlpath)
let request = NSURLRequest(URL: requestURL!)
self.webviewAlaCarte.loadRequest(request)
I think it would also be a good idea to add a function that specifically loads a url string into your web view, so you can call it from both inside alaCarteUpdate(), and loadAddressUrl(), and avoid the duplicate 3x lines. I've assumed that you're loading the URL in loadAddressURL() so that you can show a local/cached document while retrieving the latest from Parse.
Technologies Used: XCode 6, iOS8, Swift
I'm loading a webpage in a uiwebview and I'm also appending a new stylesheet to the body of that webpage and overwriting some of its styles. But, there is a delay (maybe 1 second or 2) between when the webpage loads and the styles are applied so you can see the webpage before its restyled. I'm using javascript to append the new styles to the body of the webpage. How can I fix this so that the webpage will only show with the styles are already applied? Here is my code:
import UIKit
class SecondViewController: UIViewController, UIWebViewDelegate {
#IBOutlet var website: UIWebView!
var url = "http://www.fake-website-url.net"
func loadUrl() {
let requestURL = NSURL(string: url)
let request = NSURLRequest(URL: requestURL!)
website.loadRequest(request)
}
override func viewDidLoad() {
super.viewDidLoad()
website.delegate = self
loadUrl()
}
func webViewDidFinishLoad(website: UIWebView) {
var loadStyles = "var script = document.createElement('link');script.type = 'text/css';script.rel = 'stylesheet';script.href = 'http://fake-url.styles.css';document.getElementsByTagName('body')[0].appendChild(script);"
website.stringByEvaluatingJavaScriptFromString(loadStyles)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Note, I'm using Swift.
What I would do is create a property to store the downloaded page. Then override the property setter to add your custom style sheet after the page is saved to that property. Then finally load it into your Web View.
Hope that makes sense.