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.
Related
I have a back button on my answer view controller (a view controller that displays answers) if the user hits the back button I created it switches to a view that has the title of "Back" and just an empty tableview, before switching back to my main view of where all the questions to be answered are displayed. Why is this happening? Its a very brief thing, but definitely noticeable!
UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 48)];
navBar.delegate = self;
UINavigationItem *backItem = [[UINavigationItem alloc] initWithTitle:#"Back"];
[navBar pushNavigationItem:backItem animated:NO];
UINavigationItem *topItem = [[UINavigationItem alloc] initWithTitle:#"Question"];
[navBar pushNavigationItem:topItem animated:NO];
topItem.leftBarButtonItem = nil;
[self.view addSubview:navBar];
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
ViewController *controller = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:controller animated:YES completion:nil];
return true;
}
- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item
{
ViewController *controller = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:controller animated:YES completion:nil];
}
You're creating your own UINavigationBar and UINavigationItem instances and you probably shouldn't be. The situation you describe is exactly what a UINavigationController is for. When using a UINavigationController it creates the UINavigationBar and each UIViewController that you show on screen (push into the navigation controller) has its own UINavigationItem (with the title taken from the title of the view controller).
The reason you get an empty 'view' titled "Back" is that you're creating it:
UINavigationItem *backItem = [[UINavigationItem alloc] initWithTitle:#"Back"];
[navBar pushNavigationItem:backItem animated:NO];
Dispense with all of this, create a UINavigationController and make your question view controller it's root view controller, then add the navigation controller to the screen. Then when a question is answered, push the answer view controller:
[self.navigationController pushViewController:answerViewController animated:YES];
in my app from a login screen i am navigating to a class say classA , like this
classA *objUserHome = [[classA alloc]init];
[self presentModalViewController:objUserHome animated:YES];
[objUserHome release];
and ClassA is having a navigating bar and a tabbar(5 tabs in it), i have created my tab bar programmatically like this
- (void)viewDidLoad
{
[super viewDidLoad];
//Create tab bar controller and navigation bar controller
tabBarController = [[UITabBarController alloc] init];
NSMutableArray *arrControllers = [[NSMutableArray alloc] initWithCapacity:5];
//Add PunchClock to tab View Controller
PunchClock* objPunchClock = [[PunchClock alloc] initWithTabBar];
NavigationController = [[UINavigationController alloc] initWithRootViewController:objPunchClock];
NavigationController.navigationBar.tintColor = [UIColor brownColor];
[arrControllers addObject:NavigationController];
[NavigationController release];
[objPunchClock release];
//Add Time_Sheet to tab View Controller
Time_Sheet* objTime_Sheet = [[Time_Sheet alloc] initWithTabBar];
NavigationController = [[UINavigationController alloc] initWithRootViewController:objTime_Sheet];
NavigationController.navigationBar.tintColor = [UIColor brownColor];
[arrControllers addObject:NavigationController];
[NavigationController release];
[objTime_Sheet release];
//Add PTO to tab View Controller
PTO* objPTO = [[PTO alloc] initWithTabBar];
NavigationController = [[UINavigationController alloc] initWithRootViewController:objPTO];
NavigationController.navigationBar.tintColor = [UIColor brownColor];
[arrControllers addObject:NavigationController];
[NavigationController release];
[objPTO release];
//Add PunchClock to tab View Controller
CrewPunch* objCrewPunch = [[CrewPunch alloc] initWithTabBar];
NavigationController = [[UINavigationController alloc] initWithRootViewController:objCrewPunch];
NavigationController.navigationBar.tintColor = [UIColor brownColor];
[arrControllers addObject:NavigationController];
[NavigationController release];
[objCrewPunch release];
//Add PunchClock to tab View Controller
Reports* objReports = [[Reports alloc] initWithTabBar];
NavigationController = [[UINavigationController alloc] initWithRootViewController:objReports];
NavigationController.navigationBar.tintColor = [UIColor brownColor];
[arrControllers addObject:NavigationController];
[NavigationController release];
[objReports release];
// Add this view controller array into the tab bar
//self .viewControllers = arrControllers;
tabBarController .viewControllers = arrControllers;
[arrControllers release];
[self.view addSubview:[tabBarController view]];
}
And ClassA is inherited from UIViewController
now the problem is, after navigating to classA , view of classA is shifted some 4mm downwards why its so?? how can i fix this,,pls help me out ,, thanx in advance
When using storyboards and Modal Transition between 2 or more views you can encounter an error similar to the above.
If you use Modal Transition from ViewControllerA to ViewControllerZ and then attempt to Modal Transition from ViewControllerZ back to ViewControllerA sometimes the view of ViewControllerA gets pushed down the Window slightly.
This can be prevented using:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
On ViewControllerZ to go back to ViewControllerA from an event on ViewControllerZ
You might have chosen some top bar in your Interface Builder or XIB file and additionally set the navigation bar. Dont choose any top bar in the XIB file.
Try as below
[self.navigationController.view addSubview:[tabBarController view]];
After a long research i finally fixed this issue just by inheriting the class from UINavigationController instead of UIViewControler
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
my app is based on tabbar controller
now in my default view i am showing a viewController and lets say it has Button A, when user press A it should load a my tableviewController but nothing is happening??
-(IBAction)promo:(id)sender
{
aRoot= [[tableViewController alloc] initWithNibName:#"tableViewController" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:aRoot animated:YES];
}
but its not loading anything no error even???
/////////// UPDATE
i did this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
Promo *aPromo = [[Promo alloc] initWithNibName:nil bundle:nil];//button A is deifned on this VC
// then...
aNav = [[UINavigationController alloc] initWithRootViewController:aPromo];
// [pageOne release];
and in promoviewController
-(IBAction)promo:(id)sender
{atab= [[TableViewController alloc] initWithNibName:#"TableViewController" bundle:nil];
//TableViewController *atab1 = [[TableViewController alloc]initWithNibName:#"TableViewController" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:atab animated:YES];
}
You need a navigationController to push a viewController.
you can't add a viewcontroller to a uitabbar if you want to use the navigation controller.
Where you make your tab bar controller you have to do this:
MyFirstTabViewController *pageOne = [[MyFirstTabeViewController alloc] initWithNibName:nil bundle:nil];
// then...
UINavigationController *ncOne = [[UINavigationController alloc] initWithRootViewController:pageOne];
[pageOne release];
then add ncOne to the tab bar instead of the view controller. :) Then your code in the question should work (given that you're properly declaring aRoot in the header).
EDIT
Start again... choose a view based application call it TabBarTest.
Right click on classes and add three new classes. They need to be subclasses of UIViewController or UITableViewController. Lets say they're called RootViewOne RootViewTwo and SecondaryViewController.
Then open TabBarTestViewController.m
Uncomment the viewDidLoad method.
You need to now put this code in that method:
UITabBarController *tbc = [[UITabBarController alloc] init];
NSMutableArray *viewControllers = [NSMutableArray array];
RootViewOne *vc1 = [[RootViewOne alloc] initWithNibName:nil bundle:nil];
UINavigationController *nc1 = [[UINavigationController alloc] initWithRootViewController:vc1];
nc1.view.backgroundColor = [UIColor redColor];
[viewControllers addObject:nc1];
[vc1 release];
RootViewTwo *vc2 = [[RootViewTwo alloc] initWithNibName:nil bundle:nil];
UINavigationController *nc2 = [[UINavigationController alloc] initWithRootViewController:vc2];
nc2.view.backgroundColor = [UIColor blueColor];
[viewControllers addObject:nc2];
[vc2 release];
[tbc setViewControllers:viewControllers animated:YES];
[self presentModalViewController:tbc animated:YES];
Now open RootViewOne.m and in viewDidLoad put this:
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:#"Click to move through stack" forState:UIControlStateNormal];
[button addTarget:self action:#selector(moveToNextView:) forEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
Now you're going to need a custom method:
-(void)moveToNextView:(id)selector {
SecondaryViewController *page = [[SecondaryViewController alloc] initWithNibName:nil bundle:nil];
page.title = #"Next Page";
page.view.backgroundColor = [UIColor greenColor];
[self.navigationController pushViewController:page animated:YES];
[page release];
}
This is only basic, but you should get an understanding of the kinad process you need to go through. I typed this straight into the browser so there may be spelling mistakes... watch out if you get any errors or warnings. Hopefully this can help you with your project.
Finally i solved this , i changed that VC to Navigation view Controller and then i can push the new view based on button tap,, thanks to thomas also who helped me a lot but i couldn't figure it out.
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];