I have a non storyboard app that has a UITableView with a bunch of cells, upon clicking a cell I push a view controller with a UIWebView, the local html file is loaded based on the cell tapped.
If this UIWebView then has other links in it, I use the UIWebView delegate method shouldStartLoadWithRequest along with this code:
if(navigationType == UIWebViewNavigationTypeLinkClicked) {
//When a html link is clicked in uiwebview
NSURL *url = request.URL;
NSString *urlString = url.absoluteString;
//Get components of url
NSArray *urlComponents = [urlString componentsSeparatedByString:#"/"];
//Get last component which should be wanted file name
NSString *wantedLink = [urlComponents objectAtIndex:[urlComponents count]-1];
//Get the url without the dot
NSArray *fileComponents = [wantedLink componentsSeparatedByString:#"."];
NSString *wantedFile = [fileComponents objectAtIndex:0];
ALSDetailViewController *superDetail = [[ALSDetailViewController alloc] initWithNibName:#"ALSProtocolDetailViewController" bundle:nil];
self.alsProtocolDetailViewController = superDetail;
//Check for each wanted file name to see if it matches another file
if ([wantedLink isEqualToString:#"VTachPulseStable.html"]) {
//Open different protocol xib with html file name as parameter, and push the view in
self.alsProtocolDetailViewController.title = #"Ventricular Tachycardia With Pulse";
self.alsProtocolDetailViewController.protocolURL = wantedFile;
self.alsProtocolDetailViewController.protocolSubTitle = #"Stable Without Decompensation";
[self.navigationController pushViewController:self.alsProtocolDetailViewController animated:YES];
return NO;
}
}
This code is from my working old non-storyboard app.
Basically its reloading the same view its currently in with a new loadRequest and pushing it on top of the stack, so the user can go back to the last loadRequest.
Now with storyboard I can not figure out how to accomplish this same function with segue's, I need to invoke these actions and push the controller onto the stack.
I tried performSegueWithIdentifier but had no luck.
If I use a NSURL load request for the webview without pushing a new instance of the view controller on the stack, it works.
But I need the user to be able to go back.
Any ideas how I can accomplish this?
You can use UIWebView's goBack method:
goBack
Loads the previous location in the back-forward list.
You could add some buttons to accomplish this, in the nav bar or an extra toolbar. This is certainly better design than pushing a new view controller instance.
BTW, you can push a view controller onto itself via segues by dragging the segue to the very same view controller in storyboard.
I fixed the issue by using:
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
And getting the storyboard item by its ID, and then using the old pushViewController.
Achieved the same effect.
Related
I have my viewcontroller with view with 2 buttons. If i press button i want to get new window with search bar + data from my DB. How can I achive it without new VC ?
You basically want to bring another view into your current view controller on the press of a button.
Here will be my approach :
Make a separate class for the view (in your case the search bar and the data from the DB). Also a separate XIB for this would be handy.
Let the class be named 'PopOver'
In Popover.m :
+ (PopOverView*) createInstance {
PopOverView *xibView = [[[NSBundle mainBundle] loadNibNamed:#"PopOverView" owner:self options:nil] objectAtIndex:0];
[xibView setFrame:CGRectMake(CGRectMinXEdge + 10, CGRectMinYEdge + 10, 200, 200)];
// adjust frame according to your need
[xibView setBackgroundColor:[UIColor redColor]];
return xibView;
}
Next : In your view controller, On the tap of the button you would add the following code :
- (IBAction)buttonTapped:(id)sender {
UIView *myPopoverView = [PopOverView createInstance];
AppDelegate *appDel = [UIApplication sharedApplication].delegate;
[appDel.window addSubview:myPopoverView];
}
NOTE : I added the 'PopOver' view to the app delegate's window instead of the VC because in your case you don't want the user to interact with the view controller when you are showing the 'Popover' window. In such cases, its better to present views in the app's window.
ALSO : You can animate your view while you present it. For this, refer this link : addSubview animation
Lastly, you will need to implement your search and your DB functionality within the PopOver view class. (Don't forget to add delegates between your VC and Popover).
Hope this helps.
Thanks !
window is created by default in app delgate when you create a project in xcode and whole app is running on that window.
If I am not wrong you want to create a view and add it on a window.
create a File->New->File->iOS(UserInterface), select view name it
"YourView"
create another File->New->File->iOS(Source), select CocoaTouch class,
name it
"YourView" subclass of "UIView".
YourView *viewObj = [[[NSBundle mainBundle] loadNibNamed:#"YourView" owner:self options:nil] objectAtIndex:0];
AppDelgate *appDelObj = [[UIApplication sharedApplication] delegate];
[appDelObj.window addSubview:viewObj];
your view added on window.
i am trying to make an app in which i use tableview.
I am populating the tableview and i am able to display data in the table. Now what i am trying to do is when i click a specific cell in the tableview i want to load a particular xib file in different folder. For all other cell i want to load second tableview. i am using a storyboard.
i am using
(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([((UITableViewCell *)sender).textLabel.text isEqualToString:#"ABCD"]) {
ABCD *abcdViewController = [[ABCD alloc] initWithNibName:#"ABCD" bundle:nil];
// Push the view controller.
[self.navigationController pushViewController:ABCDViewController animated:YES];
}
// Pass the selected object to the new view controller.
NSLog(#"%#", ((UITableViewCell *)sender).textLabel.text);
MethodsViewController *methodsViewController = segue.destinationViewController;
NSString *rowTitle = ((UITableViewCell *)sender).textLabel.text;
NSDictionary *selected = [[self methodsDict] objectForKey:rowTitle];
methodsViewController.rows = [selected objectForKey:#"rows"];
methodsViewController.methodsDict = [selected objectForKey:#"methodsDict"];
}
This is the code i am using. i made this code after searching the internet.
but the problem is
but when i build and run this the first tableview is shown and when i click on the ABCD cell the xib loads but the navigation bar is covering the upper portion of the xib file and when i click on the back button in the navigation bar it takes me to the black blank page and shows a error
nested push animation can result in corrupted navigation bar
Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
and the app stops
I dont know what i am doing wrong i am new to ios
I hope you understand my problem
Thanks in advance
You have at least three possible approaches to what you are trying to do.
The easiest one is using shouldPerformSegueWithIdentifier: to control exactly when segueing as specified in IB and when pushing your ABCD view controller instead:
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender{
if ([((UITableViewCell *)sender).textLabel.text isEqualToString:#"ABCD"]) {
ABCD *abcdViewController = [[ABCD alloc] initWithNibName:#"ABCD" bundle:nil];
// Push the view controller.
[self.navigationController pushViewController:ABCDViewController animated:YES];
return NO;
}
return YES;
}
This should work pretty easily for you, since it is similar to what you have been trying to do with prepareForSegue:. The fault with your current approach using prepareForSegue: is that you are both pushing your ABCD controller and doing the segue. shouldPerformSegueWithIdentifier: allows you to cancel the segue, so to say, when you are going to push manually.
Another approach would be using manual segues:
you can create a manual segue in IB by dragging from the view controller (as opposed to dragging from the prototype table cell); you can create multiple named segues;
in your table view delegate you override tableView:didSelectRowAtIndexPath: so that it calls performSegueWithIdentifier::
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *identifierOfSegueToCall;
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:nowIndex];
if ([cell.textLabel.text isEqualToString:#"ABCD"]) {
identifierOfSegueToCall = #"ABCDSegueIdentifier";
} else {
identifierOfSegueToCall = #"XYWZCellSegueIdentifier";
}
[self performSegueWithIdentifier:identifierOfSegueToCall sender:self];
}
Finally, a third approach would be defining two different cell prototypes for your table view and segueing from each prototype cell into the appropriate view controller. This is similar to what you have already done for setting up your current segue, only you should add a new prototype cell and define a specific segue from it.
I have created split view controller with two forms in IOS application. One form consists of next button to move forward. After that i want to move backward.
The code is:
DetailViewManager *detailViewManager = (DetailViewManager*)self.splitViewController.delegate;
// Create and configure a new detail view controller appropriate for the selection.
UIViewController <SubstitutableDetailViewController> *detailViewController = nil;
SecondDetailViewController *newDetailViewController = [[SecondDetailViewController alloc] initWithNibName:#"SecondDetailViewController" bundle:nil];
detailViewController = newDetailViewController;
//detailViewController.title = [tableView cellForRowAtIndexPath:indexPath].textLabel.text;
detailViewManager.detailViewController = detailViewController;
[newDetailViewController release];
This code is working fine in next button but not in previous(that is already visited).
I want to see the previous state of the form also.
Any idea should be appreciated.
Thanks in advance.
First off, I am aware of this question being asked in a forward manner, but in this case I am asking for a backwards manner in which the Navigation Controller is already designed. With that being said...
I have a UINavigationController with three views: Table, Get, and Avail in that order that was created in IB.
When going forward, I want to go from Table to Get to Avail, but when I hit the "Back" button on Avail I want to skip over Get and go directly back to Table. Is this possible? If so, how?
Here's how I did it:
NSArray *VCs = [self.navigationController viewControllers];
[self.navigationController popToViewController:[VCs objectAtIndex:([VCs count] - 2)] animated:YES];
To be able to override the nav controllers's back button you're going to have to subclass UINavigationController. Check out how in this tutorial: http://www.hanspinckaers.com/custom-action-on-back-button-uinavigationcontroller
Implement the navigation controller's delegate method:
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
It will fire for all VCs in the nav controller stack. (put this code in the VC immediately after your navigation controller, and put < UINavigationControllerDelegate > in the .h)
What you want to do is replace the entire Navigation Controller's stack without the view controller you want to remove in it. Since it's a non-mutable array, you have to convert it to a mutable array before removing the VC, remove the VC, then replace the navigation controller's stack with the call [self.navigationController setViewControllers:newVCs animated:NO];. That's the crucial part. You are replacing the stack after you have loaded the page you are on but since you're keeping the VC you're on, it's still the top item on the stack so there is no visible impact to the user. As long as you don't have a lot of VCs on the stack, it's not an expensive call.
Here's how I did it in the delegate method:
//Remove list setup page if new list was created
if ([self.navigationController topViewController].class == [ItemViewController class])
{
NSArray *VCs = [self.navigationController viewControllers];
if(((UITableViewController*)[VCs objectAtIndex:[VCs count]-2]).class == [NewCardTypeController class])
{
NewCardTypeController *removedObject = [VCs objectAtIndex:[VCs count]-2];
if(removedObject != nil)
{
NSMutableArray *newArray = [NSMutableArray arrayWithArray:VCs];
[newArray removeObject:removedObject];
NSArray *newVCs = [NSArray arrayWithArray:newArray];
[self.navigationController setViewControllers:newVCs animated:NO];
}
}
}
Take a look at UINavigationController's -popToViewController:animated: and -popToRootViewControllerAnimated:, which do exactly what you're asking for. That is, they pop the navigation stack back to a particular view controller, or to the root view controller. You'll still need to intercept the nav controller's back button action to use them, though.
I have a modal view controller that I am trying to present a web view in it. Tthe first time it appears, it shows up as blank. When I close it out and click it again, however, it displays fine. I'm thinking it may be an issue with the loading of the webView, but I've tried displaying it only when the webView finishes loading, but it never gets called then.
NSURL* newURL = [[NSURL alloc] initFileURLWithPath: fileString];
NSURLRequest *newURLRequest = [[NSURLRequest alloc] initWithURL: newURL];
[webViewController.webView loadRequest: newURLRequest];
[newURL release];
[newURLRequest release];
webViewController.modalPresentationStyle=UIModalPresentationPageSheet;
[self presentModalViewController:webViewController animated:YES];
The webView control won't be accessible the first time until the first present call causes controls to be loaded and initialized. Before the first present, webViewController.webView will be nil and so calling loadRequest on it will do nothing.
You could move the loadRequest call after the presentModalViewController call.
But instead of accessing controls in view controller's views directly, it'd be better to declare the url string as a NSString property (called say urlString) in WebViewController and set it to fileString before the presentModalViewController call (and don't create the NSURL, etc there):
webViewController.urlString = fileString;
[self presentModalViewController:webViewController animated:YES];
Finally, in WebViewController, in viewWillAppear: or viewDidAppear:, create the NSURL (using urlString), create the NSURLRequest, and call loadRequest.