I have an app that is controled through a UITabBar. In one of the sections within the tab bar, I have a navigation table. It works fine from an example I did from one of the books but I want to be able to go another view controller (aka another xib file) when the user selects a row and I want the user to be able to go back easily. I realize this has to do with pushingViewControllers but I am stuck. Here is where I think the problem is. my code is at the bottom. If you notice, I commented out
// [self presentModalViewController:flowerDetailViewController animated:YES];
While this did take me to the my flowerDetailViewController XIB file, I lost the ability to do navigation (go back). If anyone has any ideas or suggestions, it would be much appreciated.
Thank you
-(void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
FlowerDetailViewController *flowerDetailViewController =
[[FlowerDetailViewController alloc] initWithNibName:
#"FlowerDetailViewController" bundle:nil];
/*flowerDetailViewController.detailURL=
[[NSURL alloc] initWithString:
[[[flowerData objectAtIndex:indexPath.section] objectAtIndex:
indexPath.row] objectForKey:#"url"]];*/
flowerDetailViewController.title=
[[[flowerData objectAtIndex:indexPath.section] objectAtIndex:
indexPath.row] objectForKey:#"name"];
//[self presentModalViewController:flowerDetailViewController animated:YES];
[self.navigationController pushViewController:
flowerDetailViewController animated:YES];
[flowerDetailViewController release];
}
It doesn't make any sense to execute these two methods on the same view consecutively.
[self presentModalViewController:flowerDetailViewController animated:YES];
..
[self.navigationController pushViewController: flowerDetailViewController animated:YES];
because they give a very different result, from user experience point of view.
The first one presents a view modaly. Modaly means, that he application brings up the view to the top (imagine a Z-axis, when you hold the phone, it is a line from the phone to you, on top of it means closer to you), and the user is stuck in that view exclusively because it is on the top, he/she cannot touch anything else from the application unless he resolves the options presented in the view and the view goes away.
The second method is pushing the view onto he stack of views that all belong to the navigation controller. The navigation controller pushes views onto the screen like you would lay a stack of cards onto the table, card1, put onto that card 2, put onto that card 3...and so on card N. But you still have the ability to touch other options that are all around the navigation controller.To get back to the card 1, you need to remove card(views) that are on top of it, for removing on-top views, the navigation controller provides the back button automatically.
Only you cann tell, which of these two is handy in terms of your application UI and design.
Related
I have 2 views, TableController and WirelessController. While in TableController I need to pop the WirelessController view. This is what I've tried and nothing happens, no console output either.
WirelessController *wCon = [[WirelessController alloc] init];
[[wCon navigationController] popViewControllerAnimated:YES];
and this has the same problem.
[self navigationController] popViewControllerAnimated:YES];
Is it the fact that I'm using the UINavigationController when it's a view based app?
I think you mean to push, not pop...
WirelessController *wCon = [[WirelessController alloc] init];
[[self navigationController] pushViewControllerAnimated:YES];
Push adds a new item to the top of the stack; pop removes the top item from the stack.
Update
From your comments it seems that...
your first view is an instance of WirelessController.
from there you present a TableController modally
now you want to return to you wirelessController.
In this case you need to send a message back to the presenting view controller (wirelessController) asking it to dismiss the view controller it has presented (tableController)
In tableController:
[self presentingViewController] dismissViewControllerAnimated:YES
completion:nil]];
Whatever is going on, you certainly don't want to do this:
WirelessController *wCon = [[WirelessController alloc] init];
This line will create a new object. You want to return to an existing object.
Pushing and popping viewControllers is an activity generally associated with navigation controllers, which keep an array of managed viewControllers. In that case you would push to add a new controller to the top of the stack, and pop to remove it from the stack. In the absence of a navigation controller, there is no such stack, so push and pop make no sense.
For background: I'm a Windows automation and data translation "expert" (or so they say grins) in my day job. I've been dabbling with Objective-C coding off and on since I bought my first Mac in 2004.
I'm working on an IOS app. My data container class knows how to save and load from disc, and each object responds to an instance method of -(void)saveToImpliedFilename{} or -(void)save:(NSString *)filename {}. There's a static call to load the data files from storage and create distinct data objects from them (they're fairly lightweight objects, so I'm not worried about loading several at a time). The app's domain is such that many of them won't ever be loaded at once anyway.
+(NSArray *)loadData {}
That's all working fine and wonderful. In storage the objects are stored as Xml and life is good.
Where I'm having trouble is when trying to modify the tutorials so that two things happen for me:
Quick note: I'm using the tutorial as a basis for POC coding, then I'll go back and start over with the "real" coding, reusing my data objects and some of the other utility I've built along the way.
Here's my list of goals and the issues:
I want the table view to tell the data objects to save at pretty much every "edit" event. The only one I can consistently get to work is reorganizing the table's order. (the save button and adding a new entry works fine)
entering a new entry into the list creates a nice modal editor with a save and a cancel button which work wonderfully. But if I edit an existing entry, I can't reproduce the save buttons' behaviors. Each time I try, the buttons' events no longer fire. I can't figure out where I'm going wrong.
I'm using the "Editable Table View" project from this tutorial series as my basis: http://www.aboutobjects.com/community/iphone_development_tutorial/tutorial.html
In the following code, the [self isModal] test is where the save/cancel buttons are made visible and wired up. Bringing up the new-entry screen is apparently the only time it's modal. I tried wiring this stuff up so that the buttons were created all the time, but again, the events never fire for either one. The next block below is where the editable table view is called explicitly with the NEW functionality, but the nonModal view of the same tableview is called by the select event on the selector table.
So...
// code snipped for the new/modal editor
- (void)viewDidLoad {
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
// If the user clicked the '+' button in the list view, we're
// creating a new entry rather than modifying an existing one, so
// we're in a modal nav controller. Modal nav controllers don't add
// a back button to the nav bar; instead we'll add Save and
// Cancel buttons.
//
if ([self isModal]) {
UIBarButtonItem *saveButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemSave
target:self
action:#selector(save)];
[[self navigationItem] setRightBarButtonItem:saveButton];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self
action:#selector(cancel)];
[[self navigationItem] setLeftBarButtonItem:cancelButton];
}
// do stuff here to display my object...
}
// this code is called from the selection table to explicitly add a new data object.
- (void)add {
vhAddVehicleViewController *controller = [[vhAddVehicleViewController alloc] initWithStyle:UITableViewStyleGrouped];
id vehicle = [[Vehicle alloc] init];
[controller setVehicle:vehicle];
[controller setListcontroller:self];
UINavigationController *newNavController = [[UINavigationController alloc] initWithRootViewController:controller];
[[self navigationController] presentViewController:newNavController animated:YES completion:nil];
}
// this is where it's called on the table selection to show the same view without the save/cancel buttons.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
vhAddVehicleViewController *controller = [[vhAddVehicleViewController alloc] initWithStyle:UITableViewStyleGrouped];
NSUInteger index = [indexPath row];
id vehicle = [[self vehicles] objectAtIndex:index];
[controller setVehicle:vehicle];
[controller setTitle:[vehicle Vehiclename]];
[[self navigationController] pushViewController:controller animated:YES];
}
I'm assuming the issue is that presenting it makes it modal, where as pushing it doesn't...? That's fine. But when I take out the test for modal to try to keep the buttons working, no joy. The buttons draw and click when tapped, but the events don't fire.
HALP! :-)
Thanks much.
-- Chris (I logged in with my Google account so at the top of the page I'm showing as "user1820796") shrug
You forgot to call [super viewDidLoad];
Update
Try removing the cancel button that goes on the left side when pushing the view controller. See if save starts working. I think the problem is you should not add a left button to the navigation bar when the view controller is pushed.
Which method signature are you using?
- (void)save
{
NSLog(#"Saving");
}
Or
- (void)save:(id)sender
{
NSLog(#"Saving");
}
I still think this was related to push/popping the view rather than presenting the view. I switched it all to presentation and it's working how I want now.
Thanks for the assistance guys. Quite a different paradigm than I'm used to on the GUI stuff, but I'm getting there.
thanks!
I have multiple nib (xib) files and I want the user to see a different one when they tap a button. What I am looking for:
- (IBAction)buttonTap {
//Code for showing a different nib goes here
}
I can't figure out how to do this. I can show a different view within the nib file just fine, but I can't get it to show a different nib. How do I show a different nib when the user taps a button?
Any help is appreciated! Thanks!
The way I handle switching between actual xib's, and I'm sure there are a multitude of ways to accomplish the same thing, is to have my App Delegate act as a routing center between my views.
I subscribe my App Delegate to recieve events from button presses for existing views. When it recieves a request to switch views, such as a button press, I do something like this:
- (void) showLogin
{
LoginViewController *loginViewController = [[LoginViewController alloc]
initWithNibName:#"LoginViewController" bundle:nil];
// Show
self.loginViewController = loginViewController;
[loginViewController release];
self.window.rootViewController = self.loginViewController;
}
I set my rootViewController to the view I am attempting to display. It doesn't release the old controller, but simply replaces the view being displayed. You can place more logic in to determine if it's already displayed, close out other views, etc. In most simplistic terms, this works for me.
i am designing an app that has a login screen. it is a UIView with username/password and a button to submit. once the user authenticated successfully, i want to load a new xib file that holds a navigation controller and a navigation bar. below the bar i want to load a tableView and switch between other views as i move along with the programming of it.
what i did is create a new class that inherits from UINavigationController and assembled the xib file to include the navigation controller. i hooked it back up to file's owner and i'm loading the navigation controller modally like this:
myNavController* navVC = [[myNavController alloc] initWithNibName:#"navXibFile" bundle:nil];
[self presentModalViewController:navVC animated:YES];
[navVC release];
this works okay as the navigation controller shows up. however, it shows up with no title, even though i've set one up in IB. moreover, the tableView's delegates are hooked up via IB but i cannot even see empty lines. all i see is an empty navigation bar at the top and blank view (one piece) below it.
thank you for your help.
so i figured it out... first it's a design decision right? is the app being managed by a navigation controller? if so (which is my case), expect the main (first) view, that is a login page, all you need to do is to hide the navigation bar in your ViewdidLoad for the main view:
[self.navigationController setNavigationBarHidden:YES animated:YES];
once the user logs in and you push the next view like this:
MainTableViewController* mainTableVC = [[MainTableViewController alloc]
initWithNibName:#"MainTableViewController" bundle:nil];
[self.navigationController pushViewController:mainTableVC animated:YES];
[mainTableVC release];
and lastly, in the ViewDidLoad of the next view controller:
[self.navigationController setNavigationBarHidden:NO animated:YES];
in case your app needs a navigation controller for a specific section of the app but not all if it, you will need to use the VC to manage this, in a similar way the appDelegate manages the sample navigation based sample app.
i hope this helps anyone struggling with wrapping their minds around the design patterns implemented here.
cheers.
Here's the scenario: if this is a user's first time logging into my web service, I present a modal login view. Upon success, the user may have multiple items in his/her account and must choose one of them before he/she can proceed with the rest of the app.
I want to put up another modal view with a picker so the user can make the choice.
All the examples I've seen of multiple modals presented are canned ones (like the email composer modal, with the people picker modal coming up over it), which is of no use because the code isn't available.
When I try putting up the login modal, then dismissing it, then presenting the picker, I get a recursion somewhere with a selector being sent to subviews being sent to subviews being sent to ....
Can anyone point me to some sample code?
I'm keeping a reference to the login view, so I figured I'd just pose the stack (well, two) modal views, then dismiss the login modal and they'd all go away (like the documentation says), but I can't seem to get this going.
Thanks in advance.
I have found that I could do this, but had to eliminate animation on the first dismiss, iff I was using animation on the 2nd presentModalViewController
ContactsViewController* controller = [[ContactsViewController alloc] ...
UINavigationController* navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
[self.navigationController presentModalViewController:navigationController animated:YES];
[controller release], controller = nil;
and then in my delegate method that is being called from the initial modal view
[self.navigationController dismissModalViewControllerAnimated:NO]; // dismiss without animation
[self.navigationController presentModalViewController:anotherViewController animated:YES];
This behavior was observed on OS 3.0.1.