No back button on UINavigationBar inside UITabbarController - ios

I am working on an app for iOS6 and iOS7. I just found a weird behavior that varies between the two versions.
My app has a UITabbarController with 3 tabs and each tab as UINavigationController in it.
On iOS6 when I do a push on any of these navControllers the 2nd ViewController after the root does not show a back button in the navigationBar. However any subsequent pushes show the back button.
On iOS7, however, I see a back button with no title after 1st push and a back button with title "Back" after subsequent push.
Is this behavior normal? I can't understand why this is happening. How do I make sure I have a back button after every push irrespective of the OS version.
EDIT
Here is some code for clarity :
This is how I am initiating the UITabBarController
- (id)init {
self = [super init];
if (self) {
NSMutableArray *vcs = #[].mutableCopy;
JBNavigationVC *navVC = nil;
if ([JBUser sharedInstance].isLoggedIn) {
_productCategoryVC = [[JBProductCategoryVC alloc] init];
_productCategoryVC.title = #"Products";
navVC = [[JBNavigationVC alloc] initWithRootViewController:_productCategoryVC];
[vcs addObject:navVC];
_triviaVC = [[JBTriviaVC alloc] init];
_triviaVC.title = #"Trivia";
navVC = [[JBNavigationVC alloc] initWithRootViewController:_triviaVC];
[vcs addObject:navVC];
_infoVC = [[JBInfoVC alloc] init];
_infoVC.title = #"Info";
navVC = [[JBNavigationVC alloc] initWithRootViewController:_infoVC];
[vcs addObject:navVC];
}
self.viewControllers = vcs;
}
return self;
}
JBNavigationVC is a subclass of UINavigationController. This is how I transition to the tabbarVC in AppDelegate
_tabBarVC = [[JBTabBarVC alloc] init];
[_tabBarVC setSelectedIndex:0];
[self.window setRootViewController:_tabBarVC];
This sets the first VC to front. This VC is has a UITableView in it and in - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath I do this:
if (!_productsListVC) {
_productsListVC = [[JBProductsListVC alloc] init];
}
_productsListVC.category = category;
[self.navigationController pushViewController:_productsListVC animated:YES];

Related

Getting a UITabBar after breaking out of a UINavigationBar

I have a UINavigationBar that has an AuthenticateViewController in it. Then when the user his Sign In in the upper right of my navigation control, I want to show a UITabBar controller. Do I still create this in appDelegate? How do I "break out" of the UINavigation controller?
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// Add methods for layout of this view controller here
//1
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
//2
self.managedObjectContext = appDelegate.managedObjectContext;
[self.navigationItem setHidesBackButton:YES];
// Now add the Sign In button
UIBarButtonItem *signinButton = [[UIBarButtonItem alloc] initWithTitle:#"Sign In" style:UIBarButtonItemStylePlain target:self action:#selector(signinButtonPressed:)];
self.navigationItem.rightBarButtonItem = signinButton;
}
- (void) signinButtonPressed:(UIBarButtonItem *) sender
{
// What goes here to start the UITabBars
}
Set your TabBarController as rootViewController after signed in.
Your button action would be like this:
UITabBarController *tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = #[<your viewControllers>];
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
[appDelegate.window setRootViewController:tabBarController];
Edit: You might don't get use with array creation with #[]. So here is an explanation:
UIViewController *viewController1 = [[UIViewController alloc] init];
UIViewController *viewController2 = [[UIViewController alloc] init];
// Two methods of adding item to array
// First method
NSArray *array = [NSArray arrayWithObjects:viewController1, viewController2, nil];
// or
NSArray *array = #[viewController1, viewController2];
tabBarController.viewControllers = array;
You'll need to do a modalTransition to jump out of the navigationController.. this will keep the AuthenticateViewController as RootViewController of the window.. if you want to change the RootViewController as well then you'll need to get the AppDelegate's window and change its RootViewController to the TabBarController you'll make hereā€¦ hope you got it..

how to add tab bar controller from the second view controller [duplicate]

This question already has an answer here:
Showing login view controller before main tab bar controller
(1 answer)
Closed 9 years ago.
Im beginner to IOS app development learning.
I have a login screen as my first view controller and i need the second view controller to be a tab bar view controller .with 4 different tabs and i have 4 different XIB's for them.
some one help me to go ahead.
Best way you can do is Present the login screen modally when the app starts from your tab bar controller first screen, add code for presenting login screen in viewWillAppear and after login dismiss the screen. You can create TabBarController in appDelegate like this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UITabBarController tabBarController=[[UITabBarController alloc] init];
FirstViewController *firstVC = [[UIViewController alloc] initWithNibName:#"FirstVC" bundle:nil];
UINavigationController *firstNavController = [[UINavigationController alloc] initWithRootViewController: firstVC];
SecondViewController *secondVC = [[UIViewController alloc] initWithNibName:#"secondVC" bundle:nil];
UINavigationController *secondNavController = [[UINavigationController alloc] initWithRootViewController:secondVC];
tabBarController.viewControllers = [NSArray arrayWithObjects: firstNavController, secondNavController, nil];
tabBarController.selectedIndex=0;
tabBarController.delegate = self;
UITabBarItem *item1 = [[UITabBarItem alloc] initWithTitle:#"Movies" image:[UIImage imageNamed:#"MoviesTAB.png"] tag:1];
[firstVC setTabBarItem:item1];
UITabBarItem *item2 = [[UITabBarItem alloc] initWithTitle:#"Music" image:[UIImage imageNamed:#"musicTAB.png"] tag:2];
[seconfVC setTabBarItem:item2];
tabController.tabBar.translucent = NO;
tabController.tabBar.barStyle = UIBarStyleBlack;
tabBarController.tintColor = [UIColor whiteColor];
self.window.rootViewController = tabController;
return YES;
}
Best way is use storyboard and there just have one initial UIViewController and from that make segue to UITabBarViewController.
http://youtu.be/a_DCTSTv1Mw
If you want to make it through xib make a UITabBarViewController and add viewControllers to the array of object of that UITabBarViewController's object.
Sample code :
NSMutableArray *arrViewControllers = [[NSMutableArray alloc] init];
UIViewController *tabController;
UIImage *tabImage ;
NSString *tabTitle;
for (int i= 0; i < 3; i++) {
switch (i) {
case 0:
tabController = [[ViewController alloc] init];
tabImage = [UIImage imageNamed:#"icon1.png"];
tabTitle = #"Text";
break;
case 1:
tabController = [[ImageDemoViewController alloc] init];
tabImage = [UIImage imageNamed:#"icon2.png"];
tabTitle = #"Image";
break;
case 2:
tabController = [[TableDemoViewController alloc] init];
tabImage = [UIImage imageNamed:#"icon3.png"];
tabTitle = #"Table";
break;
}
// set the image and title using some properties of UIViewController
tabController.tabBarItem.image = tabImage;
tabController.tabBarItem.title = tabTitle;
//add objects to array
[arrViewControllers addObject:tabController];
[tabController release];
}
_baseController = [[UITabBarController alloc] init];
_baseController.viewControllers = arrViewControllers;
[arrViewControllers release];
go to your appDelegate
1.create a viewController for login screen.
LoginViewController *viewController1 = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
2.create a navigationController with root view your login ViewController.
UINavigationController *nVC = [[UINavigationController alloc] initWithRootViewController:viewController1];
3.make navigationController to root view of window.
self.window.rootViewController = self.nVC;
[self.window makeKeyAndVisible];
Now go to Touch-Up-Inside method of login button in LoginViewController.
1.After validation of password and userId initialise your viewControllers for tabbar and TabbarViewController.
UiViewController ...*yourViewControllers,..,
UITabBarController *YourtabBarController = [[UITabBarController alloc] init];
2.Now add these viewControllers to your tabbarController.
YourtabBarController.viewControllers = #[ YourViewController1,YourViewController2,YourViewController3,......];
3.Finally push this tabbarController to navigationControllere.
[self.navigationController pushViewController:YourtabBarController animated:NO];

Create uiTabBarController programmatically

I want to create a UIView for a UITabBarController
Here is my code for the .h file :
#interface TE : UIViewController <UITabBarControllerDelegate>{
UITabBarController *tabBarController;
}
#property (nonatomic,retain) UITabBarController *tabBarController;
#end
The viewDidLoad method:
UIViewController *testVC = [[T1 alloc] init];
UIViewController *otherVC = [[T2 alloc] init];
NSMutableArray *topLevelControllers = [[NSMutableArray alloc] init];
[topLevelControllers addObject: testVC];
[topLevelControllers addObject: otherVC];
tabBarController = [[UITabBarController alloc] init];
tabBarController.delegate = self;
[tabBarController setViewControllers:topLevelControllers animated:NO];
tabBarController.selectedIndex = 0;
self.view = tabBarController.view;
This creates the tab bar controller, but when I click on a tab bar item, I get an error:
Thread1:Program receive signal: SIGABRT
Edit: I solved the problem by downloading and modifying the version of http://www.iphonedevcentral.com/create-uitabbarcontroller/
You say above that you don't want to create the tabBarController in the appDelegate. Why not? Where else would you create it? The tabBarController has to be the root view controller and cannot be a child of any other view controller.
Btw, make sure you implement:
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
NSUInteger tabIndex = [tabBarController.viewControllers indexOfObject:viewController];
if (viewController == [tabBarController.viewControllers objectAtIndex:tabIndex] ) {
return YES;
}
return NO;
}
Subclass UITabBarController
Override the - (void) loadView method and include the following code
MyCustomViewControllerOne* ctrl1 = [[[MyCustomViewControllerOne alloc] initWithNibName#"MyViewControllerOne" bundle: nil] autorelease];
UIViewController* ctrl2 = [[[UIViewController alloc] init] autorelease];
MyCustomControllerTwo* ctrl3 = [[[UIViewController alloc] initWithObject: myObj] autorelease];
ctrl1.title = #"First tab";
ctrl2.title = #"Second tab";
ctrl3.title = #"Third tab";
ctrl1.tabBarItem.image = [UIImage imageNamed:#"tab_image1.png"];
ctrl2.tabBarItem.image = [UIImage imageNamed:#"tab_image2.png"];
ctrl3.tabBarItem.image = [UIImage imageNamed:#"tab_image3.png"];
[self setViewControllers: #[ctrl1, ctrl2, ctrl3]];
That's pretty much it.
Change self.view = tabBarController.view; to
[self.view addSubview:tabBarController.view]; And it works correctly
Trying changing
self.view = tabBarController.view;
to
[self.view addSubview:tabBarController.view];
See if that helps.
Also try placing this in your -(void)loadView method
- (void)loadView {
UIView *mv = [[UIView alloc] initWithFrame:CGRectMake(0.0, 100.0, 320.0, 480.0)];
self.view = mv;
[mv release];
}
The reason you probably are experiencing a black screen is because you haven't initialized your UIView properly.
#Mehdi, just make your TE a UITabBarController instead of a UIViewController which then has a TabBarController in it. Makes it all the more easy to manage your TabBarController. To respond to some others who have indicated that you can have only one TabBarController as the window's rootViewController. That is not the case. A UITabBarController can be instantiated in multiple places where you need a second level menu navigation. Have a TabBar within a TabBar would not make sense, but having a left Navigation Menu and then having a TabBar on each menu item would make sense.

xCode 4.2 UITableView drilldown

I'm a newbie to the xCode world and I had a few questions regarding my application setup.
My application a list of Authors, click on author and get author detail plus book titles, and then click on the book title and get book information, but I'm unable to figure out the show detail part.
I have established a tab view controller that displays UIViewControllers in the window.
//create view controllers
UIViewController *vc1 = [[HomeViewController alloc] init];
UIViewController *vc2 = [[AuthorViewController alloc] init];
UIViewController *vc3 = [[BooksViewController alloc] init];
UIViewController *vc4 = [[GenreViewController alloc] init];
UIViewController *vc5 = [[UserViewController alloc] init];
//create instance of tab bar
self.tabBar = [[UITabBarController alloc] init];
//add views to tab bar
self.tabBar.viewControllers = [NSArray arrayWithObjects:vc1,vc2,vc3, vc4, vc5, nil];
self.window.rootViewController = self.tabBar;
//self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
//self.window.backgroundColor = [UIColor whiteColor];
[_window addSubview:_tabBar.view];
[self.window makeKeyAndVisible];
return YES;
This works perfectly. My first view "AuthorViewContoller" is a table and I can display data, however I can NOT get the detailController to show.
My AuthorViewController viewDidLoad method
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.author= [[NSArray alloc] initWithObjects:#"One", #"two", nil];
self.detailController = [[AuthorDetailController alloc] init];
and my methoddidSelectRowAtIndexPath:
if(indexPath.row == 0)
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
AuthorDetailController *dc = [[AuthorDetailController alloc] initWithNibName:#"AuthorDetailController" bundle:nil];
dc.title = [author objectAtIndex:indexPath.row];
[self.navigationController pushViewController:dc animated:YES];
}else{
[self.navigationController pushViewController:detailController animated:YES];
}
I'm declaring detailController in my AuthorViewController.h file.
#property (nonatomic, retain) IBOutlet AuthorDetailController *detailController;
You have to actually create a UINavigationController, and have it be part of your controller hierarchy, before you can use pushViewController:animated:. You should really try setting this up in a NIB, instead of code, but in your code you can try this in place of your current vc2 initialization:
UIViewController *vc2 = [[UINavigationController alloc] initWithRootViewController:[[AuthorViewController alloc] init]];

navigationItem added to ABPersonViewController disappears when app resumed

I created an ABPersonViewController and added a done button:
ABRecordRef rec = ABAddressBookGetPersonWithRecordID(addrBook, recordID);
if (rec) {
ABPersonViewController* personController = [[[ABPersonViewController alloc] init] autorelease];
personController.displayedPerson = rec;
personController.personViewDelegate = self;
personController.allowsEditing = NO;
UIBarButtonItem* doneButton = [[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target: self
action: #selector(dismissModalView:)] autorelease];
UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:personController] autorelease];
[self.appViewController presentModalViewController:navController animated: YES];
// this needs to be AFTER presentModal, if not it does not show up (iOS 4 regression: workaround)
personController.navigationItem.rightBarButtonItem = doneButton;
I should have been suspicious that it had to be added AFTER the view was presented.
This worked until the app was sent to the background with this view active. When the app was restored the done button was no longer there. I've tried many ways to add this Done button but could never get it to remain through an app pause.
Here is the solution. Create an empty UIViewController in front of the ABPersonViewController. This will cause the ABPersonViewController to have a back button rather than the created done button. Override ABPersonViewController (DisplayContactViewController below) so you can implement viewDidDisappear. This will be called when the user presses the back button. In viewDidDisappear you can take down the entire navigation stack (including the empty View controller) and get back to your original view.
DisplayContactViewController* personController = [[[DisplayContactViewController alloc] init] autorelease]; //
personController.displayedPerson = rec; // the ABPersonRecord to display
personController.personViewDelegate = self;
personController.allowsEditing = NO;
personController.contactsPlugin = self; //this is my hook so I can dismiss the picker view later
// create this so DisplayContactViewController will have a "back" button.
UIViewController* parentController = [[[UIViewController alloc] init] autorelease];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:parentController];
[navController pushViewController:personController animated:YES];
[self.appViewController presentModalViewController:navController animated: YES];
Here is DisplayContactViewController viewDidDisappear.
[super viewDidDisappear: animated];
[self.contactsPlugin.appViewController dismissModalViewControllerAnimated:NO];

Resources