I got a pdf viewer in a uiwebview, from Daniel Barry http://github.com/danberry/PDF-Viewer and it works really well, it displays a pdf doc that you can scroll up and down.
Now I would like to display just one page at the time and also have a menu underneat the pdf page with a prev and next button. Can anybody help a newbe to figure out how?
Thanks!
#import "PDFViewController.h" // PDF View Controller
#implementation PDFViewController
// Synthesize UI Element properties
#synthesize webView;
// Synthesize Variable properties
#synthesize pdfURL;
#pragma mark -
#pragma mark UIViewController methods
- (void)viewDidLoad {
[super viewDidLoad];
pdfURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"stuff pdf" ofType:#"pdf"]];
[webView loadRequest:[NSURLRequest requestWithURL:pdfURL]];
webView.transform = CGAffineTransformScale( webView.transform, 1.00, 1.00 );
}
#pragma mark -
#pragma mark Memory Management
- (void)dealloc {
[webView release];
[pdfURL release];
[super dealloc];
}
#end
I think a webview should show PDFs by using a default request, no need to have a new implementation?
Anyways... There are 2 methods you could check out and link to your prev and next button
- (void)goBack:(id)sender
{
if ([webView canGoBack]) {
[webView goBack];
}
}
- (void)goForward:(id)sender
{
if ([webView canGoForward]) {
[webView goForward];
}
}
Here is the documentation of UIWebView where the methods are explained in detail: http://developer.apple.com/iphone/library/documentation/uikit/reference/UIWebView_Class/Reference/Reference.html
EDIT: Oh I think, I first misunderstood your question...
Just create an Array of the PDF URLs that you want to load. Create a counter variable that will hold the index value of the currently opened PDF.
And finally similar to the methods above create a forward and backward method and link them to the prev and next buttons. In those methods you increment or decrement the counter by 1 and load the appropriate index from the array [array objectAtIndex:counter] so the next or previous PDF is opened.
If you need more help, let me know...
ok im gonna post this as another answer...
In the header file add
NSArray *arrURLs;
NSInteger *currentIndex;
and make the array a property (retain), synthesize it in the .m file, also release it in dealloc.
In - (void)viewDidLoad initalize the array with all the URLs and set the currentIndex to 0.
arrUrls = [[NSArray alloc] initWithObjects:#"url", #"url", ..., nil];
currentIndex = 0;
add two methods that you call something like prevPage and nextPage and link them to your buttons. In those methods you do something like...
// next page
currentIndex += 1;
NSString *str = [arrUrls objectAtIndex:currentIndex];
NSURL *url = [NSURL URLWithString:str];
[webView loadRequest:[NSURLRequest requestWithURL:url]];
I would probably create another method where you set the currentIndex and check if it is in the correct bounds (e.g. should not be smaller than 0 and must be smaller than the length of the array). Than you can change the first line and let the method call handle the in/decrementing of the variable.
hope this helps.
Related
I am trying to learn Xcode by making a simple app.
But I been looking on the net for hours (days) and I cant figure it out how I make a button that open a UIWebView in another ViewController :S
first let me show you some code that I have ready:
I have a few Buttons om my main Storyboard that each are title some country codes like UK, CA and DK.
When I press one of those Buttons I have an IBAction like this:
- (IBAction)ButtonPressed:(UIButton *)sender {
// Google button pressed
NSURL* allURLS;
if([sender.titleLabel.text isEqualToString:#"DK"]) {
// Create URL obj
allURLS = [NSURL URLWithString:#"http://google.dk"];
}else if([sender.titleLabel.text isEqualToString:#"US"])
{
allURLS = [NSURL URLWithString:#"http://google.com"];
}else if([sender.titleLabel.text isEqualToString:#"CA"])
{
allURLS = [NSURL URLWithString:#"http://google.ca"];
}
NSURLRequest* req = [NSURLRequest requestWithURL:allURLS];
[myWebView loadRequest:req];
}
How do I make this open UIWebview on my other Viewcontroller named myWebView?
please help a lost man :D
Well, you've firstViewController already designed and coded, now you've to create secondViewController with a UIWebView binded in IB it self, also it have a setter NSString variable like strUrl that you need to pass at the time of pushing or presenting secondViewController, and assign it to UIWebView in viewDidLoad of secondViewController. See my answer about how to pass a NSString? Also UIWebView has its delegates method (What's delegate & datasource methods? - Apple Doc) Which you can use to handle URL request.
These are the delegate of UIWebView, if you'll going to use it, you need to give UIWebView delegate to self.
- (void)webViewDidStartLoad:(UIWebView *)webView;
- (void)webViewDidFinishLoad:(UIWebView *)webView;
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;
firstViewController.m
- (IBAction)ButtonPressed:(UIButton *)sender {
NSURL* allURLS;
//get your URL
secondViewControlelr *secondView=[[secondViewControlelr alloc]init];
second.urlToLoad=allURLS;
[self.navigationController pushViewController:secondView animated:YES];
}
secondViewControlelr.h
//declare url and set property
NSURL *urlToLoad;
secondViewControlelr.m
- (void)viewDidLoad
{
myWebView=[[UIWebView alloc]initWithFrame:CGRectMake(0, 0, 320, 460)];
[self.view addSubview:myWebView];
NSURLRequest *urlReq=[NSURLRequest requestWithURL:self.urlToLoad cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:10];
[myWebView loadRequest:urlReq];
}
I use webview in my UIVIewController and load the local HTML file in it using following method.
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:filePath]]];
If I put this method in ViewDidLoad, I can see white flicking while navigating to my controller that doesn't look good.
I tried putting this method in ViewWillAppear like below. I am using webViewLoaded flag to make sure that webview has been loaded then only show the current view else it waits but it is going in infinite loop of waiting!
- (void)viewWillAppear:(BOOL)animated {
webViewLoaded = NO;
webView.scalesPageToFit = allowZoom;
webView.dataDetectorTypes = UIDataDetectorTypeNone;
webView.delegate = self;
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:filePath]]];
int count = 0;
while(webViewLoaded == NO)
{
NSLog(#"Waiting...");
[NSThread sleepForTimeInterval:0.1];
if(count++ > 10) break;
}
}
- (void)webViewDidFinishLoad:(UIWebView *)localwebView {
webViewLoaded = YES;
}
I have also tried the same thing in ViewDidLoad but still its going in infinite loop.
Please note that webViewLoaded is "volatile BOOL" but the webview delegate method is not getting called. Not sure what's going on!
Could anyone please help me to fix this. Thanks.
First : You're blocking your main thread and not giving WebView any chance to finish loading. Never block your main thread.
Second : There are two UIWebView delegate methods : webViewDidFinishLoad and webView:didFailLoadWithError: - make sure to listen to both.
If you're trying to wait until WebView completes loading and only show your controller afterwards - use delegation or blocks. Please note that this is not a proper way of doing things - i'm just modifying your example to make it work :
child controller (with WebView) :
-(void)startLoadingWithParent:(id)_parent {
self.parent = _parent;
NSURL * url = [[NSBundle mainBundle] URLForResource:#"resource" withExtension:#"html"];
[webView loadRequest:[NSURLRequest requestWithURL:url]];
}
-(void)webViewDidFinishLoad:(UIWebView *)webView {
[parent showMe:self];
}
-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
[parent showError:error];
}
master controller :
-(void)doSomething {
SecondController * ctrl; /// secondController should be created AND has its view loaded at this point
/// ctrl = [SecondController new];
/// ctrl.view;
[ctrl startLoadingWithParent:self];
/// show user that we're doing something - display activity indicator or something
}
-(void)showMe:(UIViewController*)me {
[self.navigationController pushViewControllerAnimated:me];
}
Try using [NSURL fileURLWithPath:filePath]
use Following code for
[self performSelectorInBackground:#selector(webViewLoaded) withObject:nil];
so that it will not affect your UI
I'm getting memory leaks that i can't figure out through leaks, build/analyze or overall inspection how to repair. I have a very strong notion that it's due to the loadRequest command from my UIWebview loading javascript, but I can't figure out what's wrong.
Here's my setup:
I have a tabbarcontroller that i programatically create with 4 view controllers: a table view, a mapview, another table view and a webview, respectively.
the 1st tableview shows static data.
the mapview shows annotations that when clicked populates a variable of the 4th tab, the webview, and switches to the webview to display a locally stored html/javascript file that is a 3d model
the 2nd tableview is a listing of all the same information each annotation in the mapview represents, just in table form. it has the same functionality in terms of populating the variable, switching and displaying the html/javascript file in the webview
the webview displays the html/javascript file loaded, if not it shows a UIAlertView to select one from the mapview or the list
when i finally get to executing the loadRequest() from the webview, initially everything works fine. however, when i begin to switch between tabs and view different 3d models (i.e. go to the map view click an annotation to show say model x, watch it load in the webview, then switch to the listing table and click a row to show model y (or x too) and watch it load in the webview) i start receiving memory leaks on the ipad, not the simulator. these memory leaks are almost always: General-Block 56, 1024, 8, 244 & 24 and have no responsible frames, libraries or stack traces to follow up with.
in the webview if i comment out the loadrequest line or do a loadrequest with the request object = nil, i have no memory leaks, but when i switch to using a url object that points to the local files (i even tried pointing it to google.com, which has javascript) it erupts in memory leaks.
i've attempted to do each of these:
[self.webView loadRequest:nil];
[self.webView loadHTMLString:#"" baseURL:nil];
[self.webView stopLoading];
in viewWillDisappear of my webViewController in attempt to completely clean out the webview for reuse in the future, but it doesn't seem to be doing much help. i've also attempted doing this prior to doing the loadRequest but i get the same memory leaks.
fyi, i'm running the latest xcode 4.0.2 and the ipad has the latest update, 4.3.2
from a previous post i commented on and haven't heard back from (general-block memory leak) i believe the problem has to do with the fact that webview doesn't know how to fully rid itself of the javascript when i switch views
i did a test with a simple html file with no javascript and the general-block memory leaks are gone. however, i get other cfnetwork / http message memory leaks but that's a different story and not of my concern at the moment.
below is example code of when one of the annotations on the mapView is clicked which triggers the loadModel function in the webViewController:
- (void) mapCallOutPressed: (UIView *) sender {
NSInteger selectedIndex = sender.tag;
MyLocation *selectedObject = [_mapView.annotations objectAtIndex:selectedIndex];
MyModel *model = selectedObject.model;
NSLog(#"Model selected from mapview = %#", model.description);
// Get reference to the webview from the tabBarController (viewController's index=3)
WebViewController *webViewController = [self.tabBarController.viewControllers objectAtIndex:3];
webViewController.model = model;
[webViewController loadModel];
// Switch tabs to the webView
self.tabBarController.selectedIndex = 3;
[self.tabBarController.selectedViewController viewDidAppear:YES];
below is my webViewController.h & .m:
WebViewController.h:
WebViewController : UIViewController <UIWebViewDelegate> {
UIWebView *webView;
NSString *templateRunFilePath;
MyModel *model;
NSString *templateRunTitle;
#property (nonatomic, retain) UIWebView *webView;
#property (assign) MyModel *model;
#property (nonatomic, copy) NSString *templateRunFilePath;
#property (nonatomic, copy) NSString *templateRunTitle;
-(void) loadModel;
WebViewController.m:
- (void) viewDidLoad {
[super viewDidLoad];
NSLog(#"in webview did load");
self.webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
self.webView.delegate = self;
self.webView.autoresizingMask=(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
self.webView.scalesPageToFit = YES;
[self.view addSubview:self.webView];
}
- (void) viewWillAppear:(BOOL)animated {
if (self.model) {
self.tabBarController.navigationItem.title = [NSString stringWithFormat: #"%# - %#", self.tabBarController.navigationItem.title, self.model.description];
}
else {
UIAlertView *msg = [[UIAlertView alloc] initWithTitle:#"No Model Selected"
message:#"Please select a model from the map or list tab to view."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[msg show];
[msg release];
}
}
- (void) loadModel {
NSString *localURLPath = [NSString stringWithFormat:#"%#/%#/%#", self.templateRunFilePath, self.model.folderName, self.model.modelFileName];
NSURL *url = [NSURL fileURLWithPath:localURLPath];
NSURLRequest *requestObj = [NSURLRequest requestWithURL: url];
[self.webView loadRequest:requestObj];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[[NSUserDefaults standardUserDefaults] setInteger:0 forKey:#"WebKitCacheModelPreferenceKey"];
}
-(void)viewWillDisappear:(BOOL)animated {
NSLog(#"webview view will disappear");
[super viewWillDisappear:animated];
//[self.webView loadRequest:nil];
//[self.webView loadHTMLString:#"" baseURL:nil];
self.webView.delegate = nil;
}
- (void)dealloc {
self.webView.delegate = nil;
[self.webView release];
[super dealloc];
}
if you have any advice or corrections, i'd greatly appreciate it. i have < 1 week to figure this out and would highly thank you if you could give me any insight.
thanks!
-Mike
Mike, I am not sure whether you are doing following intentionally or by mistake?
- (void) loadModel {
[self.webView loadHTMLString:#"" baseURL:nil]; // here you are loading... or you have tried with commenting it also?
NSString *localURLPath = [NSString stringWithFormat:#"%#/%#/%#", self.templateRunFilePath, self.model.folderName, self.model.modelFileName];
NSURL *url = [NSURL fileURLWithPath:localURLPath];
NSURLRequest *requestObj = [NSURLRequest requestWithURL: url];
[self.webView loadRequest:requestObj]; // again here you are also loading?
}
I've opted to use UIWebView so I can control the layout of text I've got contained in a local html document in my bundle. I want the text to display within a UIWebView I've got contained within my view. So the text isn't the whole view, just part of it.
Everything runs fine, but when the web page loads I get a blank screen for a second before the text appears. This looks really bad. can anyone give me an example of how to stop this happening? I'm assuming I have to somehow hide the web view until it has fully loaded? Could someone one tell me how to do this?
At the moment I'm calling my code through the viewDidLoad like this:
[myUIWebView loadRequest: [NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"localwebpage" ofType:#"html"] isDirectory:NO]]];
Any help is much appreciated. I've read round a few forums and not seen a good answer to this question, and it seems like it recurs a lot as an issue for beginners like myself.
Thanks for taking the time to read this post!
UPDATED info
Thanks for your response. The suggestions below solves the problem but creates a new one for me as now when my view loads it is totally hidden until I click on my toggle switch. to understand this it's maybe most helpful if I post all my code. Before this though let me explain the setup of my view. I've got a standard view within which I've also got two web views, one on top of the other. each web view contains different text with different styling. the user flicks between views using a toggle switch, which hides/reveals the web views. I'm using the web views because I want to control the style/layout of the text. Below is my full .m code, I can't figure out where it's going wrong. My web views are called oxford & harvard I'm sure its something to do with how/when I'm hiding/revealing views. I've played around with this but can't seem to get it right. Maybe my approach is wrong. A bit of advice ironing this out would be really appreciated:
#implementation ReferenceViewController
#synthesize oxford;
#synthesize harvard;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
[oxford loadRequest: [NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"Oxford" ofType:#"html"] isDirectory:NO]]];
[harvard loadRequest: [NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"Harvard" ofType:#"html"] isDirectory:NO]]];
[oxford setHidden:YES];
[harvard setHidden:YES];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if([webView hidden]) {
[oxford setHidden:NO];
[harvard setHidden:NO];
}
}
//Toggle controls for toggle switch in UIView to swap between webviews
- (IBAction)toggleControls:(id)sender {
if ([sender selectedSegmentIndex] == kSwitchesSegmentIndex)
{
oxford.hidden = NO;
harvard.hidden = YES;
}
else
{
oxford.hidden = YES;
harvard.hidden = NO;
}
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
[oxford release];
[harvard release];
}
#end
Sure, in your UIViewController's designated initializer, set the hidden property of the UIWebView instance to YES:
[webView setHidden:YES];
Then, implement the UIWebViewDelegate method - (void)webViewDidFinishLoad:, and perform an if check inside the method like this:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if([webView hidden]) {
[webView setHidden:NO];
}
}
Also, don't forget to specify that your class conforms to the UIWebViewDelegate protocol:
#interface YourViewController : UIViewController <UIWebViewDelegate> {...}
In my iPhone app an UITextView is containing an URL. I want to open this URL in an UIWebView instead of opening it into safari?
My UITextView contains some data along with an URL. In some cases the no. of URLs can be more than one.
Thanks
Sandy
You can follow these steps:
Tick on the following properties in UITextView taken from Xib or Storyboard.
OR write these for textview taken dynamically.
textview.delegate=self;
textview.selectable=YES;
textView.dataDetectorTypes = UIDataDetectorTypeLink;
Now write the below delegate method :
-(BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
{
NSLog(#"URL: %#", URL);
//You can do anything with the URL here (like open in other web view).
return NO;
}
I think you are searching for that.
The UITextView has the capability to detect URLs and embed hyperlinks accordingly. You can turn that option on in:
myTextView.dataDetectorTypes = UIDataDetectorTypeLink;
Then you need to configure your app to trap this URL request and let your application handle it. I published a boilerplate class on github that does this, which might be the easiest route: http://github.com/nbuggia/Browser-View-Controller--iPhone-.
The first step is to sub-class UIApplication so you can override who gets to take action on the 'openUrl' request. Here's what that class might look like:
#import <UIKit/UIKit.h>
#import "MyAppDelegate.h"
#interface MyApplication : UIApplication
-(BOOL)openURL:(NSURL *)url;
#end
#implementation MyApplication
-(BOOL)openURL:(NSURL *)url
{
BOOL couldWeOpenUrl = NO;
NSString* scheme = [url.scheme lowercaseString];
if([scheme compare:#"http"] == NSOrderedSame
|| [scheme compare:#"https"] == NSOrderedSame)
{
// TODO - Update the cast below with the name of your AppDelegate
couldWeOpenUrl = [(MyAppDelegate*)self.delegate openURL:url];
}
if(!couldWeOpenUrl)
{
return [super openURL:url];
}
else
{
return YES;
}
}
#end
Next, you need to update main.m to specify MyApplication.h as being the bonified delegate for your UIApplication class. Open main.m and change this line:
int retVal = UIApplicationMain(argc, argv, nil, nil);
to this
int retVal = UIApplicationMain(argc, argv, #"MyApplication", nil);
Finally, you need to implement the [(MyAppDelegate*) openURL:url] method to have it do what ever you would like with the URL. Like maybe open up a new view controller with a UIWebView in it, and show the URL. You could do something like this:
- (BOOL)openURL:(NSURL*)url
{
BrowserViewController *bvc = [[BrowserViewController alloc] initWithUrls:url];
[self.navigationController pushViewController:bvc animated:YES];
[bvc release];
return YES;
}
Hopefully that should work for you.
Assuming you have the following instances, that are also added to your UIView:
UITextView *textView;
UIWebView *webView;
and textView contains the URL string, you can load the contents of the URL into webView, as follows:
NSURL *url = [NSURL URLWithString:textView.text];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
[webView loadRequest:req];