UIViewControllers and UIWebView - iphone

I am a newbie at iPhone development and have a question, which may end up helping understand this concept in general.
Basically, I have UIViewController which loads up a view with a bunch of stuff. Now I want when a user clicks on a button, to load up a different view, which happens to be a webView. Now, I want the weview to load up a different url depending on which button was pressed in the original view.
how do i go about doing this? Basically in my head I thought i could load and swap the views when the button is pressed, like so:
In
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *selectedLink = [valuesForSection objectAtIndex:row];
NSString *urlAddress = #"http://www.google.com";
//Create a URL object.
NSURL *url = [NSURL URLWithString:urlAddress];
//URL Requst Object
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
//Load the request in the UIWebView.
[webView loadRequest:requestObj];
[self.view removeFromSuperview];
[self.view insertSubview:webView atIndex:0];
}
Is this the right way of doing it? Or how do i go about doing this?

That would be the way I'd go about it, yes. Create a single UIWebView and, depending on which cell gets selected, load a NSURLRequest into the view using loadRequest:. It has the advantages of not requiring you to build separate web views for each cell, and of being asynchronous.
However, I wouldn't necessarily remove self.view from its superview whenever a cell gets clicked; rather, I'd pop up either a modal view controller (presentModalViewController:animated:) with the web view as its view, or I'd push a new controller onto a navigation controller stack (pushViewController:animated:). It's a smoother transition and will look better to the user.
Edit (in response to comment): Yes, it's better to have another controller than to just swap views. Doing removeFromSuperview and addSubview: keeps both views within the same controller, but as a result will make your code more difficult to manage (one controller will deal with two views) and have a worse user experience (there's no transition, like is built-in with a navigation controller push).
In order to do the push properly, you should:
Build a navigation controller for your existing view controller
When you need to, create a new instance of UIViewController with its view set to the UIWebView you create and load with your HTML
Push the new view controller onto the navigation controller stack from your old view controller by calling:
[self.navigationController pushViewController:newViewController animated:YES];

Related

UIWebView error

I am developing one application.In that first page having one UIWebView.And i create a property for that one.And i created a object for that class in another class and give the html data for that webview like as below.But it didn't show the data on UIWebView.Please tell me how to do that one.
ViewController *view=[[ViewController alloc]init];
NSString *result1 = [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding];
NSString *htmldata=[NSString stringWithFormat:#"<html>%#</html>",result1];
[view.web loadHTMLString:htmldata baseURL:nil];
This result1 string contain html data without html tag.That' why iam adding that tags.
Hope you had called pushViewController or popViewController to present the view or added the view object's view as a subview of the current view. Then make sure that the webview is allocated, given a frame and added as a subview of ViewController. You did not used the method initWithNibName:, therefor, if the webview is created from xib, it will not take.

UINavigationController, Button Click to Open URL in WebView, Located in Different View

So basically I want a UITableView to display a bunch of websites in the RootView. Then from there, using the UINavigationController, I would like to open a different view (WebViewController) and load the URL specified in the button, in the UIWebView.
What would be the best way to do this?
EDIT: Okay so there are basically two views. The first view is the RootViewController, which is includes the UINavigationController. Basically this will include some buttons (that have custom URL's already assigned to them) that will change & load the URL in the webView using the following.
-(IBAction)linkButton:(id)sender
{
NSURL *url = [NSURL URLWithString:#"http://URL_HERE.com"];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[webView loadRequest:requestObj];
}
The second view will be called the "CodeView" and it will include the UIWebView object dubbed webView.
So what I'm trying to accomplish is this: After clicking on one of the buttons in the RootViewController, it will switch to the CodeView and load whatever URL has been assigned to the button itself, in the UIWebView object. Then of course, have the option to return to the RootViewController via the UINavigationController, which is just common sense when it comes to using a Navigation Controller.
Well, you have to put the root view inside a navigation controller (i suupose you are already doing this) then for each button you tap you could create a new codeview with the url and push it to the navigation controller.
This way you could have your webview inside the codeview. Did i miss something?

How can I open a new view from a background thread without knowing what the current/main-view is?

From what I understand any new view that is opened needs to have a parent/super view.
I have a background thread that communicates with a server and according to the server's response it needs to popup an alert and in response to that alert it needs to bring up some UI. This can happen 'anywhere' within my App and so I find it hard to provide this new view with a parent/super view.
Is it possible to open this new view with no knowledge of what's currently being displayed? Is there a non-intrusive way to detect the current view and use that as the parent/super?
One of the targets is not to require anything from the Delegate and other views.
The way to get the currently visible view depends on the setup of the controllers, eg. whether you use a tab bar, navigation controller etc. I think the easiest way would be if your background thread sent a notification (using NSNotificationCenter) on the main thread whenever you need the UI changes to happen. The View Controllers can then subscribe to this notification and handle the UI changes.
Notifications are just one way of communication though, basically what you want is to have your model background thread somehow message the currently active view controller on your main thread. How you exactly go about this will largely depend on your application (see first sentence again).
Actually you don't need a view, you can add it as a subview of your app delegate's window.
In your application delegate:
- (void) showView {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,480)];
view.backgroundColor = [UIColor redColor ];
[self.window addSubview:view];
[view release];
}
Then, when you want to show the view:
MyAppDelegate *d = [[UIApplication sharedApplication] delegate];
[d showView];
You'll need a way to dismiss the view once you are done with it, you can use
[self removeFromSuperview]

Same WebView on every view

Basically i have a WebView on SecondViewController and I wish for the WebView to be visible on every view like a tab bar and fully controllable on each view.
Please note the WebView will be on a webpage with a online slideshow so I cannot simply reload on each view
Also in the SecondViewController I have
- (void)webViewDidFinishLoad:(UIWebView *)YouTubePlayer {
I would suggest adding the webView on you window after the you add the tabbarcontroller.view just like:
[window addSubview:tabbarController.view];
[window addSubview:webview];
[window makeKeyAndVisible];
and initially make don't make it visible. You should handle all the webview related methods in the app delegate. Now whenever you don't need it you can hide it by calling the methods your wrote in app delegate from your view controllers.
Hope this helps.
I'd just set up a singleton UIWebView and add it to each view-controller-view when that view controller is about to become visible. Here's one way to do it:
//.h
#interface SharedWebView : UIWebView
{
}
+ (SharedWebView*) shared;
#end
//.m
SharedWebView* g_sharedWebView;
#implementation SharedWebView
+ (SharedWebView*) shared
{
if ( g_sharedWebView == nil )
{
g_sharedWebView = [[SharedWebView alloc] init];
// ... any other intialization you want to do
}
return g_sharedWebView;
}
#end
// in your view controller(s)
#property (readonly) UIWebView* webView
- (UIWebView*) webView
{
return [SharedWebView shared];
}
- (void) viewWillAppear: (BOOL) animated
{
[super viewWillAppear: animated];
[self.view addSubview: self.webView ];
self.webView.frame = CGRectMake(10, 10, 300, 300);
// want to re-set the delegate?
// self.webView.delegate = self;
}
The simplest approach is to just make all of your view controllers aware of this extra view (make the view available through a singleton PinnedViewController or whatever). During each view controller's -viewWillAppear, just do this:
[self addSubview:[[PinnedViewController sharedController] view]];
This will move the view to whoever is currently active (making a view your subview automatically removes you from your old hierarchy).
If that is cumbersome or otherwise unworkable, there are two other options. First, you can subclass UITabViewController (I assume that's what you're using here from your question), and inject your extra view (resizing the content view to make room). This is undocumented and unsupported, so take heed. But it's not incredibly difficult if you don't do too many other fancy tricks.
The other tricky solution is to create a second UIWindow that you float over the main UIWindow (or resize the main UIWindow to make room for it). This is only semi-documented and is also not really supported. But this approach can work if you're trying to put the extra view below the tabbar for instance.
But if your system is simple enough, I recommend just letting your view controllers all manage the pinned view manually. You'll save a lot of code spelunking that way, and you won't have to rely on any undocumented internal view hierarchies.
Sounds like you try to put views on top of this view but not modal. There was this blog entry I once saw that described how you would do something like this. I think it should apply also for your case: semi-modal-transparent-dialogs-on-the-iphone
In iOS UIViewControllers are expected to manage an entire "screen" worth of content so it's not normal to try to share a single view across many view controllers. Trying to have UIViewControllers whose views only manage part of their window is problematic and will result in unexpected behavior as UIKit will not send messages like -viewWillAppear to all view controllers with visible views. Instead you would normally create a single UIViewController whose view includes that web view and whatever other views compose your tab like interface.
Alternately you could have a hierarchy of many view controllers and add a single web view as a subview of all of them. You would then pull your web view delegate behavior out into some non-UIViewController controller class to manage the behavior of the web view.
You can have all your views take up a portion of the screen and have your UIWebView take up the rest. The logic for switching between the other views should remain the same.
For example, in your viewDidLoad method for your UIViewControllers, you could have something like:
self.view.frame = CGRectMake(0, 100, 320, 380);
And in your (say) AppDelegate, you would have your normal call to show the main UIViewController (in your case, it sounds like a UITabBarController?) and also have a call to add the UIWebView. Say, something like:
myWebView.view.frame = CGRectMake(0, 0, 320, 100);
The view controllers and UIWebView would be independent of each other.
You see this pattern, I believe, with apps that have iAds. I've done something just like this with one of my free apps.
Hope this helps!
I got the same effect by simply adding it to the navigationController itself(if you don't have one then just add it).
works great for me in one of my apps.
Could you not use two webviews on your application and simply change the uppermost webview with your more dynamic content?

Shared NSMutableString for local html filename iphone

I am relatively new to Objective C/iPhone Development.
I am developing a simple app with two views using a Navigation controller.
The first view contains several buttons a and the second view contains a uiwebview.
The idea is that when a button is pressed it switches to the second view and the web view loads a local html file. Which html file is loaded depends on which button was pressed.
At the moment, the view successfully changes and I can specify a html file to load in the viewdidload method of the webviewcontroller. However this obviosly means that every button triggers the same html file.
Therefore I want to create a NSMutable string which can be accessed from both views(i.e set to a particular filename in the first view and then retrieved when the seoncd view loads).
I have searched the internet for hours and trued to use global variables, the singleton method and accessing a variable in the appdelegate. However no matter which method I try to implement, the uiwebview always displays the same html file(which is the first file alphabetically)
Thanks for any help given. I greatly appreciate any suggestions.
You don't have to use an NSMutableString for this.
Add a property url, just a normal NSString, to the second view controller. Before pushing the second view controller onto the navigation stack, you set that url property to the local url you want to load.
Then, in the second view controller class, implement:
- (void)setUrl:(NSString *)newUrl {
if(url != newUrl){
[url release];
url = [newUrl retain];
// [webView load.... load the new url in the webView.
}
}
This may be beyond you current knowledge, it contains some vital Objective-C code, like properties, setters and memory management, but just test it out and see what you can do to make it work.
EDIT You don't even need this property. Just implement a method like loadUrl: in the webViewController.
- (void)loadUrl:(NSString *)url {
// [webView load.... load the URL in the webView
}
Then, before pushing the webViewController, call this method with the URL you want to load. Avoids a property and gets rid of all the additional memory management code.
if (self.myWebViewController == nil) {
//initialise
webViewController *viewWeb = [[webViewController alloc] initWithNibName:#"webViewController" bundle:[NSBundle mainBundle]];
self.myWebViewController = viewWeb;
[viewWeb release];
}
[self.myWebViewController loadUrl:#"some-local-url"];
[self.navigationController pushViewController:self.myWebViewController animated:YES];
As a note, a good practice is to capitalize each classname. Now you have a class webViewController, but in Cocoa it's common to name the class WebViewController, then you can have a variable called webViewController. Also, you can clearly see whether you are dealing with object (variable) or just a class.
EDIT Updated
So I forgot about the fact that the webView will not have been loaded until your view gets loaded. To solve it you'll have to reintroduce the property I talked about earlier. This time some adjustments are made. In your webViewController class, add the following code:
- (void)viewDidLoad {
// viewDidLoad gets automatically called once the view has loaded. Here we want to load the webView.
[self loadWebView];
}
- (void)setUrl:(NSString *)newUrl {
if(url != newUrl){
[url release];
url = [newUrl retain];
// Update the webView with the newly set URL. This will not do anything if the view hasn't been loaded, since webView will still be nil. That's why we call loadWebView again when the view gets loaded, in viewDidLoad.
[self loadWebView];
}
}
- (void)loadWebView {
// Here you'll have to load the url. You can access it using `self.url`.
//[webView load...
}
Now, in the first view controller, update [self.myWebViewController loadUrl:#"some-local-url"]; to self.myWebViewController.url = #"some-local-url";.
I assume that the web view controller is initialised from the navigation controller, so why don't you just pass it that string when it is initialised. Then when a button is pressed it uses the correct string to instigate the web view controller.
Another idea, one I think you've tried, but I am not sure, is that the web view controller has a static method and value. When you press the button it then calls the static method on the web view controller. Then when web view controller is loading up, it calls a get static method of the value.