I am parsing RSS feeds and loading results into a table. When the user clicks on a story, they are taken to the web page.
At the moment I am using:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:story]];
Trouble is that this launches Safari and closes my app.
Is there a way to open the webpage in my app so to speak? I'd like the webpage to appear with a "Done" button that closes the web page and returns the user back to the table.
Any help (and code examples) are much appreciated.
You can use UIWebView in a new view controller launched via navigationController pushViewController selector, and have a toolbar item to "View in Safari" which will launch full Safari browser (and putting your app in the background/terminating).
Some example code snippets:
Assumptions:
(1) You have a view controller entitled: WebViewController (with same .xib) file.
(2) This view controller has a UIView which is subview of the main view;
#interface WebViewController: UIViewController <UIWebViewDelegate> {
UIWebView *webview;
NSString *someUrlToLoad;
}
#property (nonatomic, retain) IBOutlet UIWebView *webview;
#property (nonatomic, copy) NSString *someUrlToLoad;
In this view controller's viewDidLoad method:
-(void) viewDidLoad {
[super viewDidLoad];
[webview loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.someUrlToLoad]]];
}
You load this controller when someone clicked on the cell in your tableview:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
WebViewController *viewController = [[WebViewController alloc] initWithNibName:#"WebViewController" bundle:nil];
viewController.someUrlToLoad = <url for this cell>;
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
}
Most likely you will want to include some hook into the UIWebViewDelegate to stop/show an activity indicator in the navigation bar so the user is aware that something is happening while the page loads.
Related
I'm experiencing a few issues when trying to call a method from another class. Here's my code
Appdelegate.m
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
if ([url isFileURL]){
RootViewController *theview = [[RootViewController alloc] init];
[theview handleOpenURL:url];
}
return YES;
}
RootViewController.h
#interface RootViewController : UIViewController <UIWebViewDelegate>{
IBOutlet UIWebView* mainwebView;
}
- (void)handleOpenURL:(NSURL *)url;
#property (nonatomic, retain) UIWebView* mainWebView;
RootViewController.m
- (void)handleOpenURL:(NSURL *)url{
NSLog(#"Method handleOpenURL completed")
[mainwebView setDelegate:self];
[self.mainwebView loadRequest:[[NSurLRequest alloc] initWithURL:url];
[self performSelector:#selector(handleIt) withObject:nil afterDelay:3.0];
}
- (void)handleIt{
docView *docController = [[docView alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:docController animated:YES];
}
So, basically I'm trying to update a UIWebView and then present a modal view controller once the appdelegate calls handleOpenURL. The problem is that both of these things (updating webview and presenting view controller) refuse to work in the method handleOpenURL. They work perfectly fine in viewdidload, which makes me think it has something to do with the method being called from appdelegate.
The webview simply refuses to respond when accessed from the handleOpenURL method, and when I present the modal view controller I get the error
Warning: Attempt to present ... whose view is not in the window hierarchy!
But, again the modalview works fine when presented from viewdidload (using the time delay selector)
An explanation to why this is happening or a workaround would be great, thanks for your help.
You have to #import "docView.h" in your RootViewController.m.
Warning: Attempt to present ... whose view is not in the window hierarchy!
The warning states the view is not recognized, meaning you don't have access to the class properly, if it's not importing, then you didn't set up the code in docView.m properly.
If that doesn't work, than i need more info to help solve your problem.
Edit for Clarification:
The app-delegate is called at the start and when pointed to, not
constantly.
You should call it from when the modal view loads, a method
pointer([self myFunctionNameHere];) would work just fine.
So it's that your not accessing the app-delegate properly.
I don't think you should even be calling it from the app-delegate,
call it from your .m.
Calling it from your main(.m) file would solve everything.
I am new to Iphone and I have started an application in which I have added a custom tab bar which has to load to some particular page only. The tab bar works as per my expectation. Now the problem is that, when I navigate to other pages the tab bar keeps on showing and it cause serious problem for me...
Here is my implementation
In .h:
#import <UIKit/UIKit.h>
#class MainMenuViewController;
#interface RoutineListViewController : UIViewController<UITabBarDelegate>{
MainMenuViewController *homeBtn;
UITabBar *mainTabBar;
UIViewController *routineTabViewController;
UIViewController *calendarTaViewController;
UIViewController *editTabViewController;
}
#property (nonatomic, retain) IBOutlet UITabBar *mainTabBar;
#property (nonatomic, retain) IBOutlet UIViewController *routineTabViewController;
#property (nonatomic, retain) IBOutlet UIViewController *calendarTabViewController;
#property (nonatomic, retain) IBOutlet UIViewController *editTabViewController;
- (IBAction)goToHome:(id)sender;
#end
In .m, i am implementing the tab as:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
switch (item.tag) {
case 1:
if (routineTabViewController == nil) {
self.routineTabViewController =[[RoutineListViewController alloc] initWithNibName:#"RoutineListViewController" bundle:nil];
[self.view insertSubview:routineTabViewController.view belowSubview:mainTabBar];
routineTabViewController = nil;
[routineTabViewController release];
}
break;
case 2:
if (calendarTabViewController == nil) {
self.calendarTabViewController =[[CalendarTabViewController alloc] initWithNibName:#"CalendarTabViewController" bundle:nil];
[self.view insertSubview:calendarTabViewController.view belowSubview:mainTabBar];
calendarTabViewController = nil;
[calendarTabViewController release];
}
break;
case 3:
if (editTabViewController == nil) {
self.editTabViewController =[[EditTabViewController alloc] initWithNibName:#"EditTabViewController" bundle:nil];
[self.view insertSubview:editTabViewController.view belowSubview:mainTabBar];
editTabViewController = nil;
[editTabViewController release];
}
break;
default:
break;
}
}
And when I implement a button to go to some other page, the tab bar keeps showing. Here is the button implementation in EditTabViewController.m file.
- (IBAction)goToHome:(id)sender {
homeBtn = [[MainMenuViewController alloc] initWithNibName:#"MainMenuViewController" bundle:nil];
[self.view addSubview:homeBtn.view];
}
Per Apple's rules, a TabBarController is supposed to be the main container. Plus, if you just implement a custom UITabBar, are you using that to push the user into other views? If so, if the UITabBar disappears, how does the user ever return?
If you only want the bar visible when a particular page is visible, why not implement a UINavigationController (as the main container) and have the root UIViewController implement a UIToolbar that performs the same functions. Then, when you navigate to another page (I'm assuming here that you mean a new screen, not a different page in a UIPageControl or a web page in a UIWebView), you push in a new UIViewController that doesn't contain the UIToolbar.
Kind of like this:
--UINavigationController
|
-->UIViewController as RootViewController --> Contains UIToolbar
|
-->Pushes UIViewController --> Has no UIToolbar
Edit/Update
I just saw your code, and I'm not sure I understand what you're trying to achieve. I think you might be trying to somehow implement behavior similar to a UINavigationController without actually using one.
Edit/Update #2
I think you are wanting behavior that can be implemented like this:
UINavigationController (containing IconMenuViewController as RootViewController)
|
--> PageViewController (push into this from any icon touch in IconMenuViewController)
--> Contains UIToolbar/UITabBar
If you use the hierarchy above, the UINavigationController will automatically provide you with the NavigationBar at the top of the screen and give you a back button. As long as you make the UIToolbar or UITabBar part of the PageViewController, it should appear and disappear with its view controller as you push and pop it. Does that make sense?
I want to integrate one sample code with (for example SampleCode project) my iPhone application .In the sample code in firstViewController is added in MainWindow.xib and linked to viewController created in the below code.
#interface SampleCodeAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
firstViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet firstViewController *viewController;
and viewController instantiated with initWithCoder and when firstView is appeared on tap of button Camera can be opened be calling OpenCamera method as in the below code.
//in firstViewController.mm file
- (id)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
}
[self initLocal];
return self;
}
//to open camera in SampleCode application
- (IBAction)OpenCamera {
UIApplication *app = [UIApplication sharedApplication];
SampleCodeAppDelegate* delegate = [app delegate];
UIViewController* uiViewCont = [delegate viewController];
((CCamera*)m_pCamera)->Camera(uiViewCont);
}
In my navigation based application (MyApplication) I want to call firstViewController of SampleCode with one of viewController MyApplicationViewControllerA directly without adding to MyApplicationAppDelegate.
So I want to if I am creating the delegate in MyApplicationViewControllerA viewController that should work as the appdelegate in SampleCode application.
I am not able to open the camera but after closing the camera I am not able to open any other view of MyApplication except MyApplicationViewControllerA.
I am trying pushViewController and modalViewController not able to render other View.
I am not confused about the delegate. So I want to know what is the difference between AppDelegate(in SampleCodeAppDelegate : NSObject <UIApplicationDelegate>) and delegate declared in other ViewContrller.
I am trying pushViewController and modalViewController not able to render other View.
answer:
If you are not able to show other view after camera overlay screen then I think you need to show other view by performing action on main thread using performSelectorOnMainThread
[self performSelectorOnMainThread:#selector(showOtherView) withObject:OtherViewControllerObj waitUntilDone:YES];
and in the showOtherView selector method first you need to confirm that you should push the viewconroller in the navigationconroll and if that is already pushed then you should try to show otherview using presentModalViewController like below code.
-(void)showOtherView{
[self.navigationController pushViewController:OtherViewControllerObj animated:YES];
[self presentModalViewController:OtherViewControllerObj animated:YES];
}
I think this should work.
I have an app with tabbar and webview. I'm trying to make the app come back to default url each time user taps the bar. Right now I'm intercepting taps and launching a method, however it's not affecting my webview (it's not loading the page). The method works properly when called from the class, but not when it's called from my app delegate, where I'm intercepting taps.
I suspect it's something with the way I create the SecondViewController object that it's not pointing to the webview, but I have no clue what I'm doing wrong.
Here is the code:
Second view header (where the WebView is located)
#interface SecondViewController : UIViewController {
IBOutlet UIWebView *secondView;
}
- (void) goToPage;
Second view implementation
#import "SecondViewController.h"
#implementation SecondViewController
- (void)awakeFromNib
{
[self goToPage];
}
- (void) goToPage
{
NSLog(#"go to page");
NSString *newURL = [NSString stringWithFormat:#"http://pageurl"];
[secondView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:newURL]]];
}
My app delegate, where I call the SecondViewController class method:
#import "RedDragonAppDelegate.h"
#import "SecondViewController.h"
#implementation RedDragonAppDelegate
#synthesize window;
#synthesize rootController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after application launch
[window addSubview:rootController.view];
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
NSLog(#"didSelectViewController %d", rootController.selectedIndex);
SecondViewController * sv = [[SecondViewController alloc] init];
if (rootController.selectedIndex == 0){
//NSLog(#"if in didSelectViewController 0");
} else if (rootController.selectedIndex == 1) {
//NSLog(#"if in didSelectViewController 1");
[sv goToPage];
}
}
Thanks fot your help!
If I understand correctly, you've got an instance of SecondViewController with secondView connected to an instance of UIWebView in Interface Builder. What you want to do is call goToPage on that instance of SecondViewController from RedDragonAppDelegate. (In particular, note that I'm talking about instances of these--I believe this is the underlying issue.)
In tabBarController:didSelectViewController:, when you do SecondViewController * sv = [[SecondViewController alloc] init];, you are creating a new instance of SecondViewController and you can call its goToPage method, but sv is not the same instance of SecondViewController that appears in Interface Builder and has secondView connected to the UIWebView (that is, when you create a new instance of SecondViewController, the ivar secondView is unset and seems to be nil, but I don't know that it's guaranteed to be nil).
What you probably(*) want to do is add IBOutlet SecondViewController *sv; to the #interface of RedDragonAppDelegate, make sure that you have an instance of RedDragonAppDelegate in Interface Builder, connect the new IBOutlet sv of RedDragonAppDelegate to the instance of SecondViewController in Interface Builder, and delete the line in tabBarController:didSelectViewController: that defines and initializes sv.
(*) I'm not 100% certain on this because I don't do iPhone stuff and I don't know how your various views/objects/etc. are arranged in XIB/NIB files, but if everything's in one XIB/NIB file, I'm pretty sure it'll work.
I have a navigation-based application with 2 UIViewControllers (controller-2 is pushed onto controller-1 when the user selects a particular row within a UITableView displayed using controller-1).
Here's the 'twist'… When controller-1 is loaded, I want to "prefetch" a URL containing HTML/javascript into a UIWebView. Initially, the user won't see this UIWebView. Instead they will see a UITableView allowing them to click on 5 different options (row0, row1, row2, row3, row4).
When the user selects a row I would like to push a new view onto the stack and "pass" the HTML/Javascript to a UIWebView located within this new view, and display the web-page in the new view.
Is it possible to pass the UIWebView like this?
I've tried the following, which is not displaying the HTML within UIWebView, so any suggestions on how to pass the UIWebView (or alternatives) would be great. I'm pretty sure I've made the correct connections within my nib file for controller2.
To explain my motives. I want to use javascript to hide certain elements of the web-page depending on which row the user clicks. To me, it's faster and easier to make 1 URL request and then use javascript to hide various HTML elements than it is to make 5 different URL requests, fetching 5 separate web-pages. So, if there are alternative thoughts to this approach, that would be great, too. I thought about doing this all within 1 viewcontroller (adding and removing subviews), but I'd rather push onto a new view to take advantage of the navigation controller.
TYVM!!!!
////////// controller 1 //////////////////////
- (void)viewWillAppear:(BOOL)animated {
// do other stuff ///
NSURLRequest *request_object = [NSURLRequest requestWithURL:self.url];
[self.web_view1 loadRequest:request_object];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.view_controller2 = [[[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil] autorelease];
self.view_controller2.web_view2 = self.web_view1;
[self.navigationController pushViewController:self.view_controller2 animated:YES];
}
//////////// controller 1 //////////////////////
//
///////////// portion of controller 2 header file /////////////////////////
#interface ViewController2 : UIViewController {
IBOutlet UIWebView *web_view2;
}
#property (nonatomic, retain) IBOutlet UIWebView *web_view2;
//////////// portion of controller 2 implementation file //////////////
#import "ViewController2.h"
#implementation ViewController2
#synthesize web_view2;
- (void)dealloc {
[web_view2 release], web_view2 = nil;
[super dealloc];
}
//////////// controller 2 //////////////////////////
You've got the right idea, but you need to do one other thing. In your -tableView:didSelectRowAtIndexPath:. you need to add the webview to the viewController's view, not just assign it to an outlet. The following might work, depending on your XIB files:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.view_controller2 = [[[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil] autorelease];
self.web_view1.frame = self.view_controller2.web_view2.frame;
[self.view_controller2.web_view2 removeFromSuperview];
self.view_controller2.web_view2 = self.web_view1;
[self.view_controller2.view addSubview: self.web_view1];
[self.navigationController pushViewController:self.view_controller2 animated:YES];
}
This assumes that web_view2 is a valid and hooked up outlet, containing a webview in the location you want your 'cached' view to be.