IOS. UITabBarController with navigationController - ios

I had a viewController which contains video view and UITabBarController. UITabBarController contains 3 viewControllers with UINavigationController. The problem is that the frame of first UINavigationController is good (0,20,width,height), but the other two navigationController has wrong frame (0,0,width,height). Status bar is showing, so I don't know what's wrong with them.
Here i create TabBarController :
#interface EEMenuTBC ()
#end
#implementation EEMenuTBC
- (void)viewDidLoad {
[super viewDidLoad];
EEFavoritesVC *favotiteVC = [[EEFavoritesVC alloc] initWithNibAsClassName];
UINavigationController *favotiteNC = [[UINavigationController alloc] initWithRootViewController:favotiteVC];
[favotiteVC.tabBarItem setImage:[UIImage imageNamed:#"favoritesMenuDisabled"]];
[favotiteVC.tabBarItem setTitle:#"Favourites"];
EESearchTVC *searchVC = [[EESearchTVC alloc] initWithNibAsClassName];
UINavigationController *searchNC = [[UINavigationController alloc] initWithRootViewController:searchVC];
[searchVC.tabBarItem setImage:[UIImage imageNamed:#"searchMenuDisabled"]];
[searchVC.tabBarItem setTitle:#"Search"];
EESettingsTVC *settingsVC = [[EESettingsTVC alloc] initWithNibAsClassName];
UINavigationController *settingsNC = [[UINavigationController alloc] initWithRootViewController:settingsVC];
[settingsVC.tabBarItem setImage:[UIImage imageNamed:#"settingsMenuDisabled"]];
[settingsVC.tabBarItem setTitle:#"Settings"];
self.viewControllers = #[favotiteNC, searchNC, settingsNC];
self.tabBar.items[0].selectedImage = [UIImage imageNamed: #"favoritesMenuEnabled"];
self.tabBar.items[1].selectedImage = [UIImage imageNamed: #"searchMenuEnabled"];
self.tabBar.items[2].selectedImage = [UIImage imageNamed: #"settingsMenuEnabled"];
for(UIView *temp in self.tabBar.subviews) {
[temp setExclusiveTouch:YES];
}
}
-(BOOL)prefersStatusBarHidden {
return NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)goToRootVC {
if (_delegateMenuTBC && [_delegateMenuTBC respondsToSelector:#selector(EEMenuTBCDelegateGoToRootVC)]) {
[_delegateMenuTBC EEMenuTBCDelegateGoToRootVC];
}
}
#end
In other ViewController i doing
_menuTBC = [[EEMenuTBC alloc] initWithNibName:#"EEMenuTBC" bundle:nil];
_menuTBC.view.frame = self.view.frame;
And in favotiteVC navigation look's good, and all other's 2 navigations has no spacing from status bar
P.S
First of all, I added my UITabBarController as a child to UIViewController. The first UINavigationController from UITabBarController has right frame (0,20,width,height) , but others 2 UINavigationsControllers, has wrong frame (0,0,width, height). I think they don't have status bar, and I checked that method -prefersStatusBarHidden isn't call from all UIViewControllers which contains in UITabBarController

Related

UINavigationBar with UISegmentedControl partially covers childViews

I have read many other threads on this and the Apple docs, but haven't found a solution yet for my particular problem.
My app uses a UITabBarController as the rootViewController, and in one of the tabs I have a UISegmentedControl in the navigationBar to switch between three child UITableViewControllers.
(In the real app two of the childVCs are a custom UIViewController, I'm just using three UITableViewControllers for the sample app).
The segmentedControl setup and the switching all works fine. The thing that goes wrong is that only the first UITableViewController is shown correctly. For the second and third one, part of the first cell is hidden under the navigationBar. When I click through all three, the first one is still ok.
I have made a little sample app to show what's going on, using very bright colors for demonstration purposes: https://www.dropbox.com/s/7pfutvn5jba6rva/SegmentedControlVC.zip?dl=0
Here is also some code (I'm not using storyboards):
// AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
FirstViewController *fvc = [[FirstViewController alloc] init];
UINavigationController *firstNavigationController = [[UINavigationController alloc] initWithRootViewController: fvc];
SecondViewController *svc = [[SecondViewController alloc] init];
UINavigationController *secondNavigationController = [[UINavigationController alloc] initWithRootViewController: svc];
// Initialize tab bar controller, add tabs controllers
UITabBarController *tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = #[firstNavigationController, secondNavigationController];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
// FirstViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.title = #"One";
self.view.backgroundColor = [UIColor orangeColor];
UITableViewController *vc1 = [[UITableViewController alloc] init];
UITableViewController *vc2 = [[UITableViewController alloc] init];
UITableViewController *vc3 = [[UITableViewController alloc] init];
vc1.view.backgroundColor = [UIColor redColor];
vc2.view.backgroundColor = [UIColor blueColor];
vc3.view.backgroundColor = [UIColor greenColor];
self.viewControllers = #[vc1, vc2, vc3];
self.segmentTitles = #[#"Red", #"Blue", #"Green"];
self.segmentedControl = [[UISegmentedControl alloc] initWithItems: self.segmentTitles];
[self.segmentedControl addTarget: self
action: #selector(segmentClicked:)
forControlEvents: UIControlEventValueChanged];
self.navigationItem.titleView = self.segmentedControl;
self.segmentedControl.selectedSegmentIndex = 0;
// set the first child vc:
UIViewController *vc = self.viewControllers[0];
[self addChildViewController: vc];
vc.view.frame = self.view.bounds;
[self.view addSubview: vc.view];
self.currentVC = vc;
}
- (void)segmentClicked:(id)sender
{
if (sender == self.segmentedControl)
{
NSUInteger index = self.segmentedControl.selectedSegmentIndex;
[self loadViewController: self.viewControllers[index]];
}
}
- (void)loadViewController:(UIViewController *)vc
{
[self addChildViewController: vc];
[self transitionFromViewController: self.currentVC
toViewController: vc
duration: 1.0
options: UIViewAnimationOptionTransitionFlipFromBottom
animations: ^{
[self.currentVC.view removeFromSuperview];
vc.view.frame = self.view.bounds;
[self.view addSubview: vc.view];
} completion: ^(BOOL finished) {
[vc didMoveToParentViewController: self];
[self.currentVC removeFromParentViewController];
self.currentVC = vc;
}
];
}
So obviously my question is, why does this happen, and what can I do to fix it?
Edit: adding screenshots.
EDIT: Based on the answer below I changed the code in the animation block to:
[self.currentVC.view removeFromSuperview];
if ([vc.view isKindOfClass: [UIScrollView class]])
{
UIEdgeInsets edgeInsets = UIEdgeInsetsMake(self.topLayoutGuide.length, 0, self.bottomLayoutGuide.length, 0);
[UIView performWithoutAnimation: ^{
vc.view.frame = self.view.bounds;
((UIScrollView *)vc.view).contentInset = edgeInsets;
((UIScrollView *)vc.view).scrollIndicatorInsets = edgeInsets;
}];
}
else
{
vc.view.frame = self.view.bounds;
}
[self.view addSubview: vc.view];
Now it works. I'm going to try this with a custom UIViewController as well.
The issue is that you do not set the correct content inset to each table view. The system attempts to do it for you, but I guess your setup is too complex for it, and it only does it for the first tableview that is loaded in viewDidLoad. In your loadViewController: method, when replacing the currently displayed view, make sure to set both the contentInset and scrollIndicatorInsets to the values of the previous view. I think the system will manage to set the correct insets later, in case you rotate to landscape. Try it. If it doesn't, you will need to do it on your own in viewDidLayoutSubviews.

iOS: Make navigation bar always visible in UITableViewController

I have searched and searched and have been unable to find an answer to my problem.
I have a Table View Controller and I need the navigation bar to always be visible at the top of the screen and not scroll up along with the table view. I've seen solutions suggesting I adjust the content inset, set it to translucent, etc. None of those work. If you can provide any solutions/suggestions I would be very appreciative!
-(void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBarHidden = NO;
self.navigationController.navigationBar.translucent=YES;
self.tableView.contentInset = UIEdgeInsetsMake(44,0,0,0);
self.automaticallyAdjustsScrollViewInsets = NO;
self.edgesForExtendedLayout=UIRectEdgeNone;
self.extendedLayoutIncludesOpaqueBars=NO;
self.automaticallyAdjustsScrollViewInsets=NO;
if ([UIScreen mainScreen].scale > 1.0)
{
[self->btnBack setImage:[UIImage imageNamed:#"back_button#2x.png"]];
}
else
{
[self->btnBack setImage:[UIImage imageNamed:#"back_button.png"]];
}
self.tableView.separatorColor = [UIColor colorWithRed:69/255.0 green:189/255.0 blue:150/255.0 alpha:1.0];
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:#"nav_bar_bg.png"] forBarMetrics:UIBarMetricsDefault];
NSLog(#"Loading up coupons");
MWRAppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
if([g_categoryName isEqualToString: #"All"]){
NSMutableArray *coupons = [appDelegate getAllCoupons];
NSMutableArray *contests = [appDelegate getAllContests];
NSArray *newArray=[contests arrayByAddingObjectsFromArray:coupons];
self.fetchedRecordsArray = newArray;
}
else {
NSMutableArray *coupons = [appDelegate getCatCoupons];
NSMutableArray *contests = [appDelegate getAllContests];
NSArray *newArray=[contests arrayByAddingObjectsFromArray:coupons];
self.fetchedRecordsArray = newArray;
}
[self.tableView reloadData];
}
You can try to embed your UITableViewController in an UINavigationControler.
Using Storyboard : select your UITableViewController, press Editor > Embed in > Navigation controller.
Or by code, create a UINavigationController and set your tableviewcontroller as its rootviewcontroller :
UINavigationController* aNavigationController = [[UINavigationController alloc] initWithRootViewController:yourTableViewController];
and present aNavigationController instead of presenting yourTableViewController ;-)
ps: if yourTableViewController is not embeded in a navigation controller, then calling self.navigationController will just return nil and any action on it would be nil too.

Right Button won't show in custom Navigation Controller

My app is a tab bar app with many navigation controllers.
I want these navigation controllers to handle login/logout actions with a custom right bar button. So I've set up my tab bar in AppDelegate this way :
MyFirstViewController *firstViewController = [[MyFirstViewController alloc] init];
UIViewController *firstNavigationController = [[CustomNavigationController alloc]
initWithRootViewController:firstViewController];
MySecondViewController *secondViewController = [[MySecondViewController alloc] init];
UIViewController *secondNavigationController = [[CustomNavigationController alloc]
secondViewController]
initWithRootViewController:secondViewController];
....
[tabBarController setViewControllers:#[firstNavigationController, secondNavigationController]];
Then CustomNavigationController :
#implementation ConnectionNavigationController
- (void) viewDidLoad
{
[self displayConnectionButton];
}
- (void) displayConnectionButton
{
UIImage *portraitImage, *landscapeImage;
portraitImage = [UIImage imageNamed:#"conn.png"];
landscapeImage = [UIImage imageNamed:#"connLandscape.png"];
UIBarButtonItem *connButton = [[UIBarButtonItem alloc]
initWithImage:[portraitImage
imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
landscapeImagePhone:[landscapeImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
style:UIBarButtonItemStylePlain target:self action:#selector(showConnectionPopup)];
self.navigationItem.rightBarButtonItem = connButton;
}
#end
I tried with viewDidLoad, viewDidAppear, viewWillAppear but nothing works, I can't get this button to show in the navigation bar. I also tried to add reloadInputViews or setNeedsDisplay. What should I do?
Thanks for your help
Edit : interface of CustomNavigationController
#interface ConnectionNavigationController : UINavigationController
- (void) displayConnectionButton;
#end
From what I understand you should add the displayConnectionButton method to the relevant UIViewController subclass and not to your UINavigationController subclass as this only contains the stack of view controllers.
E.g.
#implementation MyFirstViewController
- (void) viewDidLoad
{
[self displayConnectionButton];
}
- (void) displayConnectionButton
{
UIImage *portraitImage, *landscapeImage;
portraitImage = [UIImage imageNamed:#"conn.png"];
landscapeImage = [UIImage imageNamed:#"connLandscape.png"];
UIBarButtonItem *connButton = [[UIBarButtonItem alloc]
initWithImage:[portraitImage
imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
landscapeImagePhone:[landscapeImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
style:UIBarButtonItemStylePlain target:self action:#selector(showConnectionPopup)];
self.navigationItem.rightBarButtonItem = connButton;
}
#end
As a note if you put a breakpoint on your displayConnectionButton in your CustomNavigationController and po self.viewControllers I think you will get an empty array (i.e. no view controllers)

use storyboard with custom UITabbarController

i have been working on this issue for some time now and cannot find a solution to my problem.
i have a tabbar view controller that i have tried to customise with images, i have the custom graphics working however i need to use code to display and init the tabbar's view controllers. i also have a problem with displaying a navigation bar at the top of one of my tabs which i think is connected to how i am initiating the tab view controllers
the storyboard shows that there should be a navigation bar at the top of the medication tab and that the view is connected to the tab bar via a segue
you can see i have tried to use storyboard segues to link my view controllers to the tab bar controller. i have the following code in the MedicationViewController.m
/
// MedicationViewController.m
// fibromapp
//
// Created by jamie mcallister on 08/09/2013.
// Copyright (c) 2013 Jamie McAllister. All rights reserved.
//
#import "MedicationViewController.h"
#import "TakenViewController.h"
#import "MedsListViewController.h"
#import "MedsAlarmViewController.h"
#interface MedicationViewController ()
#end
#implementation MedicationViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
TakenViewController *viewController2 = [[TakenViewController alloc] init];
MedsListViewController *viewController1 = [[MedsListViewController alloc] init];
MedsAlarmViewController *viewController3 = [[MedsAlarmViewController alloc] init];
self.viewControllers = [NSArray arrayWithObjects:viewController1,
viewController2,
viewController3,nil];
UITabBarItem *tab1 = [[UITabBarItem alloc] initWithTitle:#"Medication" image:[UIImage imageNamed:NULL] tag:1];
UITabBarItem *tab2 = [[UITabBarItem alloc] initWithTitle:#"Taken" image:[UIImage imageNamed:NULL] tag:2];
UITabBarItem *tab3 = [[UITabBarItem alloc] initWithTitle:#"Alarms" image:[UIImage imageNamed:NULL] tag:3];
UIImage* sel = [UIImage imageNamed:#"fmtabSel"];
[viewController1 setTabBarItem:tab1];
[viewController2 setTabBarItem:tab2];
[viewController3 setTabBarItem:tab3];
UIImage* tabBarBackground = [UIImage imageNamed:#"fmtab.png"];
UITabBar *tabBar = self.tabBar;
[tabBar setBackgroundImage:tabBarBackground];
[tabBar setSelectionIndicatorImage:sel];
}
return self;
}
- (void)viewDidLoad
{
UITabBar *tabbar = self.tabBar;
NSLog(#"%f %f", tabbar.frame.size.width, tabbar.frame.size.height);//used to find the size of the bar
[super viewDidLoad];
UIImage* tabBarBackground = [UIImage imageNamed:#"fmtab.png"];
UIImage* sel = [UIImage imageNamed:#"fmtabSel"];
UITabBar *tabBar = self.tabBar;
[tabBar setBackgroundImage:tabBarBackground];
[tabBar setSelectionIndicatorImage:sel];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
with this code i get the tab but there is no navigation bar at the top of this tab.
can anybody suggest what i must do to resolve this?
if you require any more information feel free to ask and i will edit it into the bottom of this question.
thanks in advance :)
To have a Navigation bar, you have to put a UINavigationController between the tabbar controller and the first UIViewController.
All can be done in storyboard without needs of writing a line of code.
If you want the navigation bar to be at the top You should fill your tabbar controller with navigation controllers inited with root controllers, not just plain controllers.
Smth like that:
TakenViewController *viewController2 = [[TakenViewController alloc] init];
MedsListViewController *viewController1 = [[MedsListViewController alloc] init];
MedsAlarmViewController *viewController3 = [[MedsAlarmViewController alloc] init];
UINavigationController * nc1 = [[UINavigationController alloc] initWithRootViewController:viewController1];
UINavigationController * nc2 = [[UINavigationController alloc] initWithRootViewController:viewController2];
UINavigationController * nc3 = [[UINavigationController alloc] initWithRootViewController:viewController3];
self.viewControllers = [NSArray arrayWithObjects:nc1,
nc2,
nc3,nil];

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.

Resources