Title and bar button not displaying in navigation bar - iphone

I'm having some strange difficulties with setting a title and adding a bar button to my navigation bar.
My app is a Tabbed application. The problem is within my first tab. The first tab consists of a UINavigationController, that contains a UITableViewController. From my AppDelegate:
UIViewController *firstViewController = [[MyTableViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
_tabBarController = [[TFTabBarController alloc] init];
_tabBarController.delegate = self;
_tabBarController.viewControllers = [NSArray arrayWithObjects:navigationController, nil];
On selecting a row in firstViewController, I push a UIWebViewController on the navigation stack:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIViewController *secondViewController = [[MyWebViewController alloc] init];
[self.navigationController pushViewController:secondViewController animated:YES];
}
On intercepting the onclick of a hyperlink in the WebView, I push another UITableView on the navigation stack:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *url = [request URL];
if (navigationType == UIWebViewNavigationTypeLinkClicked)
{
UIViewController *thirdViewController = [[MyTableViewController alloc] init];
[self.navigationController pushViewController:thirdViewController animated:YES];
return NO;
}
return YES;
}
As thirdViewController opens, its navigation bar only contains the back button with the title of the previous view to navigate back. Its title and the right bar button are not shown...
This is how I try to display them:
self.title = #"My Title";
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Push me" style:UIBarButtonItemStylePlain target:self action:#selector(push)];
I also tried setting the button through the navigationController, but still no luck:
self.navigationController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Push me" style:UIBarButtonItemStylePlain target:self action:#selector(push)];
What could I be doing wrong here?

Check that self.navigationItem and self.navigationController are not nil when accessed.
From the documentation:
The first time the property is accessed, the UINavigationItem object is created. Therefore, you shouldn’t access this property if you are not using a navigation controller to display the view controller.
A good place to access these members is under -viewDidLoad and not upon initialization.

Related

Adding UINavigationController to View Other Than Main View

I'd like to add a UINavigationController to my app info view (NOT to my main view). I've watched/read a number of tutorials showing how to add it to the main window through the AppDelegate using IB. In my case, I only want it to appear when a user presses the info button and is brought to the infoView. Here is how I switch to the infoView within my MainViewController:
- (IBAction)infoButtonPress:(id)sender
{
// Create pointer to instance of InfoViewController
InfoViewController *infoView = [[InfoViewController alloc] initWithNibName:#"InfoViewController" bundle:nil];
// Add view switching animation
infoView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
// Change view using animation
[self presentModalViewController:infoView animated:YES];
}
At this point the infoView is displayed and I would like THIS to be the RootView of the UINavigationController. I have tried adding the line:
UINavigationController *infoNavController = [[UINavigationController alloc]
initWithRootViewController:infoView];
after creating an instance of InfoViewController, but the app crashes. Is it possible to add UINavigationController to views other than the main view?
Thanks.
You are very close with your implementation. Try it in this order.
InfoViewController *infoView = [[InfoViewController alloc] initWithNibName:#"InfoViewController" bundle:nil];
UINavigationController *infoNavController = [[UINavigationController alloc]
initWithRootViewController:infoView];
[infoView release]; // skip this if using ARC
infoView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:infoNavController animated:YES];
UPDATE
To kill this modal, you will have to add your buttons to the main modal view.
InfoViewController.m
-(void)cancel:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
-(void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *cancelButton =
[[UIBarButtonItem alloc] initWithTitle: #"Cancel"
style: UIBarButtonItemStylePlain
target: self
action: #selector(cancel:)];
self.navigationItem.leftBarButtonItem = cancelButton;
[cancelButton release];
}

Why is viewWillDisapper not called?

Why is viewWillDisapper not called when I push back button in navigation bar of myViewController?
TheController *theController = [[TheController alloc] initWithStyle:UITableViewStylePlain];
UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:theController];
self.naviController = aNavigationController;
[aNavigationController release];
[theController release];
[self.view addSubview:naviController.view];
// This is TheController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
MyViewController *myViewController = [[MyViewController alloc] init];
[self.navigationController pushViewController:myViewController animated:YES];
[myViewController release];
}
// This is MyViewController.m.
MyViewConroller is subclass of UIViewController.
- (void)viewWillDisappear:(BOOL)animated {
// I want to override back button behavior. But, this is not called.
}
viewWillAppear, viewDidAppear, viewDidDisappear, viewDidUnLoad are not called either.
If you just want to override the left navigation bar button behavior, you can simply replace the leftBarButtonItem with a button with a custom action:
// Place this in you viewDidLoad method
UIBarButtonItem *customBack = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonSystemItemCancel target:self action:#selector(customAction)];
self.navigationItem.leftBarButtonItem = customBack;
[customBack release];
You can also provide a custom view for the UIBarButtonItem if you prefer.
You should call viewWillAppear in your parent view controller.
http://bit.ly/q9vQiu

pushViewController issue

I've got a TabBar application and 2 views.
One view is a MKMapView with annotations and callouts etc. All works well. Clicking on the 'UIButtonTypeDetailDisclosure' button in the callout my 'showDetails' function fires (NSLOG..).
Now I want to push a DetailView in 'showDetails'. I'd have to either use pushViewController or presentModalViewController
#pragma mark - MKMap methods
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation{
if([annotation isKindOfClass:[CustomPlacemark class]])
{
MKPinAnnotationView *newAnnotation = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:[annotation title]];
newAnnotation.pinColor = MKPinAnnotationColorGreen;
newAnnotation.animatesDrop = YES;
newAnnotation.canShowCallout = YES;
newAnnotation.enabled = YES;
//newAnnotation.pinColor=MKPinAnnotationColorPurple;
NSLog(#"Created annotation at: %f %f", ((CustomPlacemark*)annotation).coordinate.latitude, ((CustomPlacemark*)annotation).coordinate.longitude);
[newAnnotation addObserver:self
forKeyPath:#"selected"
options:NSKeyValueObservingOptionNew
context:#"GMAP_ANNOTATION_SELECTED"];
UIImageView *leftIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"leftIconView.png"]];
newAnnotation.leftCalloutAccessoryView = leftIconView;
[leftIconView release];
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:annotation.title forState:UIControlStateNormal];
[rightButton addTarget:self
action:#selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
newAnnotation.rightCalloutAccessoryView = rightButton;
[newAnnotation autorelease];
return newAnnotation;
}
return nil;
}
- (void) showDetails:(id)sender {
NSLog(#"Annotation Click");
[self.navigationController pushViewController:self.detailViewController animated:YES];
// I want to push a new View here...
}
Unfortunately this doesn't do anything (No error / no action). I reckon it's because I don't have a navigationController to use pushViewController.
- (void) showDetails:(id)sender {
NSLog(#"Annotation Click");
[self.navigationController pushViewController:self.detailViewController animated:YES];
// I want to push a new View here...
}
i am trying to create and push a DetailViewController in the navigationController when my 'UIButtonTypeDetailDisclosure' button in notification is clicked. but navigationController is nil
Any idea what to add to my 'showDetails' function?
Much appreciated
You need to have a navigation controller before pushing views on it:
DetailViewController *detailController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:[NSBundle mainBundle]];
// this line calls the viewDidLoad method of detailController
detailController.view.hidden = NO;
UINavigationController *navigationController = [[UINavigationController alloc] detailController];
navigationController.navigationBarHidden = YES;
[navigationController setView:detailController.view];
[self.view addSubview:navigationController.view];
[detailController release];
[navigationController release];
Be careful this will initialize navigationController again and again if you do this in your showDetails:. So you need to initialize your navigation controller in eg. viewDidLoad and then you will be able to push your detailController onto it
If you want to push a view controller with a navigation controller, then your initial view must be within the navigation controller to begin with.
In your case, your tab bar controller should probably be put in the navigation controller if it isn't already. Then you can call your showDetails method the way you have done above. If it is in the nav controller, maybe you can post the code where you do that and I can try and offer more assistance.
Here is how you might do something like this in your applicationDidFinishLaunchingWithOptions: method
FirstViewController *fvc = [[FirstViewController alloc] init];
SecondViewController *svc = [[SecondViewController alloc] init];
UITabBarController *tabcon = [[UITabBarController alloc] init];
tabcon.viewControllers = [NSArray arrayWithObjects:fvc,svc,nil];
UINavigationController *navcon = [[UINavigationController alloc] initWithRootViewController:tabcon];
[self.window addSubview:navcon.view];
Then when you want to push a detail view controller, you just call:
DetailViewController *dvc = [[DetailViewController alloc] init];
[self.navigationController pushViewController:dvc];
If you set your view controllers as properties, you can call self.viewControllerName, just make sure you are allocating memory for them as well. Embedding your tab bar controller in a navigation controller like this gives you all the window dressing (back buttons, title bar, etc.) for free and it will adapt to your different views as they come on screen.

problem in UITable cell selection

hai ,
i have coded in UITableview in the method as follows.but when i touch the cell or row ,it wont
go to the next page(navigation did not work).have i to declare navigation conroller in other file.but i have coded app delegate in applicationdidfinishmethod for tab bar through dynamic.how can i link navigation?
the code:
UITableview;(TableViewController)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
SubController *nextController = [[SubController alloc] init];
[self.navigationController pushViewController:nextController animated:YES];
[nextController release];
}
appdelegation:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
tabBarController = [[UITabBarController alloc] init];
tabBarController.navigationItem.title = #" News";
TableViewController *rtbfViewController = [[TableViewController alloc]
init];
rtbfViewController.tabBarItem.title = #"News";
InfoViewController *infoViewController = [[InfoViewController alloc]
initWithStyle:UITableViewStyleGrouped];
infoViewController.tabBarItem.title = #"Info";
tabBarController.viewControllers = [NSArray
arrayWithObjects:rtbfViewController,infoViewController,nil];
tabBarController.customizableViewControllers = [NSArray arrayWithObjects:nil];
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
}
The problem is, that you don't have a UINavigationController, so self.navigationController in your TableViewController is nil (and thus messages sent to this property are ignored). You should modify your code in the app delegate as follows:
// [...] create tab bar view controller...
// create navigation controller with TableViewController instance as root view controller
TableViewController *rtbfViewController = [[TableViewController alloc] init];
rtbfViewController.tabBarItem.title = #"News";
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:rtbfViewController];
// [...] create other view controllers
// NOTE: add the navigation controller to the tab bar controller, rather than the TableViewController
tabBarController.viewControllers = [NSArray arrayWithObjects:navController,infoViewController,nil];
tabBarController.customizableViewControllers = [NSArray arrayWithObjects:nil];
And don't forget to release your view controllers afterwards:
[rtbfViewController release];
[navController release];
[infoViewController release];

Implement Back action into UITabBarController

I have a controllerView (MenuControllerView) with a button inside, when I click on the button a new ViewController will appear with a TabBarController created programmatically like this:
UIView* topView = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,480)];
tabBarController = [[UITabBarController alloc] init];
viewController1 = [[ViewController1 alloc] init];
viewController2 = [[ViewController2 alloc] init];
viewController3 = [[ViewController3 alloc] init];
viewController4 = [[ViewController4 alloc] init];
tabBarController,viewControllers = [NSArray arrayWithObjects:viewController1 , viewController2 , viewController3 ,viewController4, nil];
[[self tabBarController] setSelectedIndex:1];
[topView addSubView:[tabBarController view]];
Instead of displaying ViewController1 for the first button Item, I want to put an action Back in it to return to my MenuViewController, but I don't know how how to do it.
Thanks
Have you considered presenting the UITabBarController as a modal view controller and implementing UITabBarControllerDelegate? e.g. this seems to work for me (I make the third tab return to MenuViewController here):
#interface MenuViewController : UIViewController <UITabBarControllerDelegate>
...
- (IBAction) onButtonPressed:(id)sender
{
UITabBarController* tabBarController = [[UITabBarController alloc] init];
viewController1 = [[ViewController1 alloc] init];
viewController2 = [[ViewController2 alloc] init];
viewController3 = [[ViewController3 alloc] init];
tabBarController.viewControllers = [NSArray arrayWithObjects:viewController1 , viewController2 , viewController3 , nil];
[[self tabBarController] setSelectedIndex:1];
tabBarController.delegate = self;
[self presentModalViewController:tabBarController animated:NO];
}
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController;
{
if (viewController == viewController3)
{
[self dismissModalViewControllerAnimated:NO];
return NO;
}
return YES;
}
I doubt that this approach is a good one. You'll gonna break typical iPhone behaviour which will confuse users. The TabBarController is designed (functionally and technically) to change between views while a NavigationController is for pushing and popping views (go forth and back). Of course you can combine those (which is not always easy), but you shouldn't use TabBar as NavigationBar.
if I understand right, you can just remove your tabbar's view from superview. smth like
[[tabBarController view] removeFromSuperview];
if you just want to handle selection of tabbar item, you can use tabBar:didSelectItem: method of th UITabBarDelegate protocol.
Is this what you're trying to do?
This automatically created with a UINavigationController upon pushing to a child view controller.
[self.navigationController pushViewController:yourChildViewController animated:YES];