Tab bar controller not appearing correctly - objective-c

I'm trying to connect Tab Bar Controller to existing part of my app, but when I do that it's "malfunctioning".
However when I run Tab Bar Controller part standalone as initial view controller it works properly like in the image below :
This is how app looks when it is run(correct behavior) :
However when I go to this tab bar controller from my main app this is how it looks like this:
My main app looks like this :
Scroll View contains
UIView 1
UIView 2
UIView 3
UIView x
Each view does something not related to this tab bar controller. Only one view view x tries to "visit" tab bar controller and display some data there, but it's not. Any ideas?
I have this tab bar controller identifier set to test, and I here is how I do that from my view x :
UITabBarController *newViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"test"];
[self.view addSubview:newViewController.view];
EDIT :
Entire app :
I'm creating views programatically. That's why I don't have any relationships/segues to the tab bar controller.
SOLUTION :
Change :
UITabBarController *newViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"test"];
[self.view addSubview:newViewController.view];
To :
UITabBarController *newViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"test"];
[self addChildViewController:newViewController];
[self.view addSubview:newViewController.view];

You need to set a root viewController to the navigation Controller

Just don't do this. From the Apple UITabBarController referenece
Because the UITabBarController class inherits from the UIViewController class, tab bar controllers have their own view that is accessible through the view property. When deploying a tab bar interface, you must install this view as the root of your window. Unlike other view controllers, a tab bar interface should never be installed as a child of another view controller.
As I understand it means you must use UITabBarController only as a root view controller of the window. But you can alway use a general UIViewController and add UITabBar there.
(The view offset problem you've met is possible to be fixed, it will not follow the Apple guidelines however and not advised).

Related

Putting a Navigation Controller inside a UIScrollView

I have a UIScrollView that houses three UIViewControllers so that I can swipe between them like the view setup in SnapChat.
In my ViewController on the very right of the UIScrollView I want the user to be able to select things and then navigate to a new page. So essentially I want the right-most UIViewController to be a Navigation Controller with a nav bar and and View Controllers I navigate to from this page should also have a nav bar and a Back button as the UIBarButtonItem in the top left as standard.
I went about it the normal way, just taking the View Controller and selecting "Embed In Navigation Controller" and looking at the storyboard it looks right, but if I run it, there's no nav bar at the top of the view controller.
I have the nav bar visibility set to "Show Navigation Bar" but still nothing.
Any help appreciated
Edit
The issue is more than likely to do with how I add the view controller to the UIScrollView which is as follows:
let settingsStoryboard = UIStoryboard(name: "SettingsView", bundle: nil)
let settingsViewController = settingsStoryboard.instantiateViewController(withIdentifier: "SettingsViewController")
self.addChildViewController(settingsViewController)
self.scrollView!.addSubview(settingsViewController.view)
So I'm only adding the view. So how would I add it as a Navigation Controller? Or can that be done?
The Problem you are facing is that you are adding your view controller directly inside the scroll view but you should add the navigation controller inside the ScrollView.
So go to story board create a StoryboardID for that navigationController which is attached to SettingsViewController and then replace the SettingViewController ID with your navigationController's Storyboard ID.
maybe use addChildViewController
- (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(5_0);

How to get current viewController class name?

but the problem is that my app has both UInavigationController and UITabBarController
so calling navigaionController.topViewController tells me that i have UItabBarController
and
self.window.rootViewController returns UINavigationController
thank's a lot
You can check for the kind of class it is using
[VC isKindOfClass:(myVCClass class)]
The tabbarcontroller is designed to be the top/root viewcontroller of your application. From the documentation:
Because the UITabBarController class inherits from the UIViewController class, tab bar controllers have their own view that is accessible through the view property. When deploying a tab bar interface, you must install this view as the root of your window. Unlike other view controllers, a tab bar interface should never be installed as a child of another view controller.
Have the navigationcontroller inside the tabs and have the other view controllers inside the navigationcontrollers on the tabs.
view.class returns a class name as a string:
NSLog (#"Class:%#", view.class);

Add a XIB view to a tab view in the storyboard

I am working on an Iphone application.
I am using a StoryBoard.
I have a Tab View with 3 tabs. "Home", "Users" and "Settings".
I create the "Home" and "Users" view on the story board, but The settings view is a XIB file (SettingsView.xib)
How can I make the third tab ("Settings") open the SettingsView.xib? Can I use both the story board and xib files?
I tried to initialize a UINavigationController in the startApp method in the AppDelegate but I can't find out how to add it to the story board.
Thanks for any help
TabViewControllers usually have one navigation controller for each tab.
Create the navigation controllers in storyboard and connect them to the navigationcontrollers relation of the tab view controller.
The initial view of the navigation controller connects to the rootViewController relationship of the navigation controller.
As to your second question, I'm not certain, but I think the following will work:-
Create a UIViewController in storyboard and change it's class to your class that you're loading from an XIB. When the storyboard instantiates the class, it will use the XIB provided the class name of the class exactly matches the name of the XIB. I don't think you can do any iPad/iPod checking here though.
You can add a xib-based view to your storyboard-based tab bar controller as follows. I am assuming the following:
The tab bar controller is the initial view controller of your storyboard.
Your settings controller is a class called SettingsController
You have a tab bar image in your bundle called SettingsTabImage
Define the tab bar controller in the storyboard with just your storyboard-based tab bar items in it - Home and Users in your case
In your application delegate, use the following code in application:didFinishLaunchingWithOptions::
// Create your settings view controller
SettingsController *settingsVC = [[SettingsController alloc] initWithNibName:nil bundle:nil];
// Create a tab bar item
UITabBarItem *settingsItem = [[UITabBarItem alloc] initWithTitle:#"Settings" image:[UIImage imageNamed:#"SettingsTabImage" tag:0];
settingsVC.tabBarItem = settingsItem;
// Get a reference to the tab bar controller
UITabBarController *tbC = (UITabBarController*)self.window.rootViewController;
// Get the current view controllers in your tab bar
NSMutableArray *currentItems = [NSMutableArray arrayWithArray:tbC.viewControllers];
// Add your settings controller
[currentItems addObject:settingsVC];
tbC.viewControllers = [NSArray arrayWithArray:currentItems];

Pushing a navigation controller is not supported- performing segues

I created a new navigation controller in my storyboard (not programmatically!) and set it to be "Root View Controller" to a regular UIViewController and added a button in it which says- forward to the next view controller (this second view controller is a view controller which I want that will have a back button to link to the initial view controller).
Now, whenever I try to link the button to the next view controller- "Pushing a navigation controller is not supported".
Help me please, and thanks
EDIT:
I accidentally subclassed UINavigationController, and not UIViewController in my class.
Thank you anyway.
I've tried this and have no problems, its all done in IB with no additional code required ...
Start a new project, "Single View Application" using story boards
Select storyboard and delete the views its produced.
Drag on a new Navigation Controller (it will bring a table view with it)
Delete the table and the table view controller, so you are just left with the Navigation Controller
Drag on a normal view controller
Right Click and drag from the Navigation controller to the new View and choose "Relationship - Root View Controller"
Drag a "Bar Button Item" on to the Navbar which should be visible on the top of your ViewController, you can rename this Forward if you wish.
Now drag on another view controller which is the one your "Forward" button will push in to view.
Right Click and drag from the bar button to the 2nd View Controller, and choose "Push"
Run the project and you will get a Single view with a Navbar and your button, clicking your button will Push the other view and give you a Back Button to return to the first View Controller. I'll try and post a picture of my storyboard if it helps.
Plasma
I had the same trouble. I wanted to have a navigation controller on each storyboard, so that each could run independently, be individually debugged, and so that the look would be right with the navigation bar.
Using other approaches, I found the UINavigationController would be retained from the original storyboard -- which I didn't want -- or I'd get errors.
Using the AppDelegate in your view controller to set the rootViewController worked for me (borrowing segue naming conventions from Segue to another storyboard?):
- (void)showStartupNavigationController {
NSLog(#"-- Loading storyboard --");
//Get the storyboard from the main bundle.
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Startup" bundle:nil];
//The navigation controller, not the view controller, is marked as the initial scene.
UINavigationController *theInitialViewController = [storyBoard instantiateInitialViewController];
NSLog(#"-- Loading storyboard -- Nav controller: %#", theInitialViewController);
//Remove the current navigation controller.
[self.navigationController.view removeFromSuperview];
UIWindow *window = [(AppDelegate *)[[UIApplication sharedApplication] delegate] window];
window.rootViewController = theInitialViewController;
To swap views Programatically you would need to select the segue and give it an Identifier like "PushView" then call it like this ....
[self performSegueWithIdentifier:#"PushView" sender:self];
That will programatically do the same as clicking the forward button. I've created you an example project with the code discussed above. Has an -(IBAction) with code in you can use for programatially changing the view.
PushView.zip
I also wanted to do this, present a screen (that had an embedded navigation controller) when the user pushes a button.
At my first attempt, I connected the segue from the button in the fist screen to the Navigation Controller, and the app was crashing with this error "Pushing a navigation controller is not supported".
This is the solution I found:
Select the segue from the button in the first screen to the navigation controller.
If it had an identifier, copy its name. Then delete that segue.
Then create a new segue by CTRL-clicking the button in the first view controller and dragging to the VIEW CONTROLLER YOU WANT TO PRESENT (not to the Navigation Controller that is pointing at it), and select Push in the small pop up window.
Then click the icon in the middle of the segue and paste the name you copied in the first step as an identifier for it.
IB is going to give you a warning "Scene is unreachable due to lack of entry points and does not have an identifier for runtime access via -instantiateViewControllerWithIdentifier:." Don't worry, it works perfectly.
If you want to customize the string that is shown as the Back button to return, you can add this line in the viewDidLoad method OF THE VIEW CONTROLLER THAT IS BEING SHOWED AFTER THE BUTTON IS PRESSED, that is the Child view controller.
(replace "Settings" with the name you need)
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBar.topItem.title = #"Settings";
...
}

Adding Navigation from home page

I'm adding navigation to subviews in my app from the home view.
I understand the concepts of pushing and popping view in the navigation stack, however, I don't want the navigation bar in the home screen.
Basically, when the user leaves the home view to any sub view, I'd like them to see the "Home" button on the left of the button nav bar, but no nav bar in the home view.
Any help would be appreciated.
It sounds like you want to start out with a bare UIViewController, containing your home screen with your own custom buttons.
The UINavigationController should come into play only when a user performs some action. Do this by
[navVC setModalTransitionStyle:UIModalTransitionStyleCrossDissolve]; // pick an effect
[self.viewController presentModalViewController:VC animated:YES];
Where navVC is the navigation controller, and self.viewController refers to your (new) main view controller. (add a suitable line IBOutlet UIViewController *viewController; + #property line + #synthesize line)
You need to fiddle a bit in the way the app starts up, for now it will probably show the navigation controller directly. If you are using a xib, you can do this by adding a UIViewController while leaving the navigation controller there as it stands. In application: didFinishLaunchingWithOptions: you'll find a line saying
[window addSubview:...];
which actually determines which viewcontroller's view is first visible. Change this to:
[window addSubview:self.viewController.view];
If you've done all this correctly, you've inserted the extra UIViewController between startup and navigation.