UITabBarController only showing half of its UITabBar (off screen) - iphone

My UITabBar is not completely showing after I present a UITabBarController from a UIViewController. Please can you tell me what I am doing wrong?
My code is:
//some method
LoggedInViewController *lvc = [[[LoggedInViewController alloc] initWithAccount:account] autorelease];
[self presentModalViewController:lvc animated:YES];
- (void)viewDidLoad
{
self.tabController = [[UITabBarController alloc] init];
LoggedInFeedNavigationController *navController = [[LoggedInFeedNavigationController alloc] initWithAccount:self.account];
[self.tabController setViewControllers:[NSArray arrayWithObject:navController]];
[self.view addSubview:self.tabController.view];
[super viewDidLoad];
}

It's not a good practice to do:
[viewController1.view addSubview:viewController2.view];
The point of the MVC design is lost. The view controller should get your data (from the model) and put it in the view. If you have more than one view just arrange the functionality of the views to accept the corresponding data.
So if you need a tab bar controller you should do the following:
// assuming you are in the same initial controller
UITabBarController* pTabBarControllerL = [[UITabBarController alloc] init];
MyFirstController* pFirstControllerL = [[MyFirstController alloc] init];
[pTabBarControllerL setViewControllers:[NSArray arrayWithObject:pFirstControllerL]];
// perhaps set more tab bar controller properties - button images and so on
[self presentModalViewController:pTabBarControllerL animated:YES];
// release the memory you do not need
-(void)viewDidLoad {
// do your work in pFirstControllerL
}
PS: You should not subclass UINavigationController and UITabBarController.

Actually according to the Apple's recommendations UITabBarViewController should be the root in the UIWindow hierarchy. We had hard times trying to put TabBar VCs or Navigation VCs not to the root.

Related

How to code a back button on the a navigation bar using a bar button item

I'm having trouble coding a button to go to the previous page. I was able to do it to go to the next page thinking if I did the same thing but changed it a bit it would work in reverse. Unfortunately, I come up with a lot of errors I can't resolve because it won't allow me to use the release function.
This is this the code that helps it to work going to the next page fine:
#import "ViewController.h"
#implementation ViewController
-(IBAction)btnClicked:(id) sender
{
//add the view of the view controller to the current View---
if (menuView==nil) {
menuView =
[[MenuView alloc] initWithNibName:#"MenuView"
bundle:nil];
}
[self.view addSubview:menuView.view];
}
-(void)dealloc {
[menuView release];
[super dealloc];
}
How do I do it so that a back button will go to the previous page though.
It's pretty simple, use this :
-(IBAction)back:(id) sender
{
[menuView.view removeFromSuperview];
}
But, I would suggest not using addSubview: for many views as it would be complex way to do. Use UINavigationController as #Paul.s suggested.
The way you are doing this is not quite correct and I would suggest doing some reading to get familiar with iOS programming.
Your program structure should be: create a navigation controller (2) to manage the stack of view controllers giving it a viewController (1) to act as it's root.
// AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// 1
FirstViewController *firstViewController = [[FirstViewController alloc] init];
// 2
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
[firstViewController release]; firstViewController = nil;
self.window.rootViewController = navigationController;
[navigationController release]; navigationController = nil;
[self.window makeKeyAndVisible];
return YES;
}
This will display your first view controller inside a UINavigationController. A UINavigationController is responsible for managing a stack of UIViewController's and giving you UI to navigate back down the stack as well as calling all the appropriate presentation related methods on a UIViewController at the correct times e.g. viewDidLoad. You should check out The View Controller Programming Guide for lots of info
Then inside your first view controller you do something like this to respond to the button:
- (IBAction)buttonClicked:(id)sender;
{
SecondViewController *secondViewController = [[SecondViewController alloc] init];
[self.navigationController pushViewController:secondViewController animated:YES];
[secondViewController release]; secondViewController = nil;
}
This creates a new view controller and pushes it onto the stack.

Right design pattern for tabbed navigation views?

I've been stuck trying to puzzle this out for a couple days now, and I'll admit I need help.
The root view controller of my application is a tab bar controller. I want to have each tab bar a different navigation controller. These navigation controllers have completely different behavior.
So how do I set this up in terms of classes? Per Apple's documentation, I'm not supposed to subclass UINavigationViewController. So where do I put the code that drives each of these navigation controllers? Does it all get thrown in App Delegate? That would create an impossible mess.
This app should run on iOS 4.0 or later. (Realistically, I can probably require iOS 4.2.)
This is taken from one of my applications. As you say, you are not supposed to subclass UINavigationController, instead you use them as they are and you add viewcontroller on the UINavigationController's. Then after setting the root viewcontroller in each UINavigationController, you add the UINavigationController to the UITabBarController (phew!).
So each tab will "point" to a UINavigationController which has a regular viewcontroller as root viewcontroller, and it is the root viewcontroller (the one you add) that will be shown when a tab is pressed with a (optional) navigationbar at top.
UITabBarController *tvc = [[UITabBarController alloc] init];
self.tabBarController = tvc;
[tvc release];
// Instantiates three view-controllers which will be attached to the tabbar.
// Each view-controller is attached as rootviewcontroller in a navigationcontroller.
MainScreenViewController *vc1 = [[MainScreenViewController alloc] init];
PracticalMainViewController *vc2 = [[PracticalMainViewController alloc] init];
ExerciseViewController *vc3 = [[ExerciseViewController alloc] init];
UINavigationController *nvc1 = [[UINavigationController alloc] initWithRootViewController:vc1];
UINavigationController *nvc2 = [[UINavigationController alloc] initWithRootViewController:vc2];
UINavigationController *nvc3 = [[UINavigationController alloc] initWithRootViewController:vc3];
[vc1 release];
[vc2 release];
[vc3 release];
nvc1.navigationBar.barStyle = UIBarStyleBlack;
nvc2.navigationBar.barStyle = UIBarStyleBlack;
nvc3.navigationBar.barStyle = UIBarStyleBlack;
NSArray *controllers = [[NSArray alloc] initWithObjects:nvc1, nvc2, nvc3, nil];
[nvc1 release];
[nvc2 release];
[nvc3 release];
self.tabBarController.viewControllers = controllers;
[controllers release];
This is how I go from one viewcontroller to another one (this is done by tapping a cell in a tableview but as you see the pushViewController method can be used wherever you want).
(this is taken from another part of the app)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (self.detailedAnswerViewController == nil) {
TestAnsweredViewController *vc = [[TestAnsweredViewController alloc] init];
self.detailedAnswerViewController = vc;
[vc release];
}
[self.navigationController pushViewController:self.detailedAnswerViewController animated:YES];
}
The self.navigationcontroller property is of course set on each viewcontroller which are pushed on the UINavigationController hierachy.

UINavigationController - basics

I'm trying to use a UINavigationController but I'm uncertain how. Up till now (for about a year), I've been using presentModalViewController and dismissModalViewController to present/dismiss view controllers.
So, this is what I did. My main view controller (the first one that shows on launch) is called MainViewController, and it extends UIViewController.
So I made this launch function in my app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
MainViewController *controller = [[MainViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
And in my MainViewController's viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"Title";
self.navigationController.navigationBar.tintColor = [Constants barColor];
....more code...
}
But, in my MainViewController, I'd like to present another view controller called SecondViewController, which needs a UINavigationBar with a back arrow button. So do I make SecondViewController extend UIViewController and do the same thing by setting the title and backButton in the viewDidLoad method? And how do I present it? What should I do to accomplish this?
You'll need to set a root view controller up, it's easiest starting from the apple template.
Here's where the magic happens:
UIViewController *controller = [[UIViewController alloc] initWithNibName:#"MyNib" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
The nav controller does all the work for you (back buttons, titles, animations) - it keeps track!
My workflow is this:
Setup MutableArray in the viewDidLoad, add controllers to it, e.g:
NSMutableArray *array = [[NSMutableArray alloc] init];
MyCustomViewController *customView = [[MyCustomViewController alloc] initWithNibName:#"nib" bundle:#"nil"];
customView.title = #"Second Level";
[array addObject:customView];
self.controllers = array;
Then in your delegate:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
UIViewController *childControllerToBe = [controllers objectAtIndex:row];
[self.navigationController pushViewController:childControllerToBe animated:YES];
}
This, along with a lot more can be learnt by reading a decent beginner book such as Beginning iPhone Development
Also, apple docs are always good :)
UINavigationController is a subclass of UIViewController, but unlike UIViewController it’s not usually meant for you to subclass. This is because navigation controller itself is rarely customized beyond the visuals of the nav bar. An instance of UINavigationController can be created either in code or in an XIB file with relative ease.
Please visit "How to add UINavigationController Programmatically"
You should Push it onto the navigation stack.
This Lecture by Stanford's iPhone Course will teach you a lot about Navigation Bars. (It's a quick read)
Basically at the heart of it you need this code:
[self.navigationController pushViewController:SecondView];
You can use PopViewController to go back programmatically, but the Back Button is automatically created.
Here's some source code from the Lecture. It covers exactly what you are having issues with.

Combining UITabController & UINavigation controller programmatically http://t.co/R52RlUL UITabController & UINavigation controller programmatically

I have created a UItabbarcontroller and 2 views with UITableViews just using code (no IB stuff) and I want to now add a navigation bar at the top that will include add and edit buttons, however I seem to be tripping up and blowing my app up or adding navgation controller to a 3rd tab only.
Here is my main code for adding the tab bar and switching views
FYI - I am using XCode4
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.mainTabBar = [[UITabBarController alloc] init];
// create the 2 views
tableViewController* vc1 = [[tableViewController alloc] init];
tableViewController2* vc2 = [[tableViewController2 alloc] init];
// put them in an array
NSArray* controllers = [NSArray arrayWithObjects:vc1, vc2, nil];
// for the tab bar
mainTabBar.viewControllers = controllers;
// Add the tab bar controller's current view as a subview of the window
[self.window addSubview:self.mainTabBar.view];
// Override point for customization after application launch.
[self.window makeKeyAndVisible];
return YES;
}
Where do you want navigation controller(s)? You have to create one for each tab you want one in the UITabBarController.
You add a navigationController in conjunction with the first view controller on its stack. Try this:
// create the controllers for UITabBarController
tableViewController *vc1 = [[[TableViewController alloc] init] autorelease];
navController *nav1 = [[[UINavigationController alloc] initWithRootViewController:vc1] autorelease];
tableViewController *vc2 = [[[TableViewController alloc] init] autorelease];
navController *nav2 = [[[UINavigationController alloc] initWithRootViewController:vc2] autorelease];
// put them in an array
NSArray *controllers = [NSArray arrayWithObjects:nav1, nav2, nil];
// rest of your code
Also note that you need to release anything you alloc or retain. You can do it as I did by adding autorelease when you initialize them or you can release them explicitly after you've added them to the controllers array.
You then configure the navigationItem for each view controller in its loadView or viewDidLoad method depending on how you implemented it.

UITabBarController to load subviews

I am kind of stuck and would appreciate any ideas on what I did wrong.
I created programmatically a NSObject which holds a UITabBarController to which three ViewControllers are added:
UITabBarController tabBarController = [[UITabBarController alloc] init];
ControllerOne = [[OneViewController alloc] initWithNibName:#"OneView" bundle:nil];
ControllerTwo = [[TwoViewController alloc]initWithNibName:#"TwoView" bundle:nil];
ControllerThree = [[ThreeViewController alloc] initWithNibName:#"ThreeView" bundle:nil];
NSMutableArray *viewControllers = [[NSMutableArray alloc] initWithCapacity:3];
[viewControllers addObject:ControllerOne];
[viewControllers addObject:ControllerTwo];
[viewControllers addObject:ControllerThree];
[tabBarController setViewControllers:viewControllers];'
I now display the tabBarController's view
viewController.modalTransitionStyle = transitionStyle;
[self presentModalViewController:viewController animated:YES];
with viewController being the just created tabBarController.
The view changes fine, displaying the tabbar correctly (Icons and titles) but fails to show e.g. OneViewController's view. I assume that the view is not loaded since the - (void)viewDidLoad is not being called for any of the subview controllers.
I would appreciate any suggestions.
Thanks,
equi
Are you sure your nib names are how you have typed them? It's not called OneViewController.xib?, for example?
I sorted out the issue.
The above code actually worked, reason for the view not appearing was that I accidentally synthesised 'view' in the UIViewController derivative.