I'm currently working with multi-storyboard project, and I'm make an custom UIView inside an UIViewController (I named it "Tab Bar VC") and make it look like a tab bar with the tutorial from this link:
https://github.com/codepath/ios_guides/wiki/Creating-a-Custom-Tab-Bar
Everything show up normally but the problem is when I press on tab bar items the navigation bar doesn't show and I can't push to another view controller without it. I have tried to embed my "Tab Bar VC" in navigation controller like this picture but it's doesn't work:
Note that in my case I don't wanna use UITabBarViewController or Storyboard Reference. Please help me.
Thank in advance.
Here is my code of Tab Bar VC:
#import "SHTabViewController.h"
#import "SHHomeViewController.h"
#import "SHTicketViewController.h"
#import "SHNotificationViewController.h"
#import "SHChatViewController.h"
#import "SHCallViewController.h"
#interface SHTabViewController () {
NSMutableArray *viewcontrollers;
NSInteger selectedIndex;
}
#property (weak, nonatomic) IBOutlet UIView *contentView;
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *tabButtons;
#property (strong, nonatomic) SHHomeViewController *homeVC;
#property (strong, nonatomic) SHCallViewController *callVC;
#property (strong, nonatomic) SHChatViewController *chatVC;
#property (strong, nonatomic) SHTicketViewController *ticketVC;
#property (strong, nonatomic) SHNotificationViewController *notifVC;
#end
#implementation SHTabViewController
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
selectedIndex = 0;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
selectedIndex = 0;
UIStoryboard *homeStoryboard = [UIStoryboard storyboardWithName:#"Home" bundle:[NSBundle mainBundle]];
UIStoryboard *callStoryboard = [UIStoryboard storyboardWithName:#"CallPM" bundle:[NSBundle mainBundle]];
UIStoryboard *chatStoryboard = [UIStoryboard storyboardWithName:#"Chat" bundle:[NSBundle mainBundle]];
UIStoryboard *ticketStoryboard = [UIStoryboard storyboardWithName:#"Ticket" bundle:[NSBundle mainBundle]];
UIStoryboard *notifStoryboard = [UIStoryboard storyboardWithName:#"Notification" bundle:[NSBundle mainBundle]];
self.homeVC = [homeStoryboard instantiateViewControllerWithIdentifier:#"homeVC"];
self.callVC = [callStoryboard instantiateViewControllerWithIdentifier:#"callVC"];
self.chatVC = [chatStoryboard instantiateViewControllerWithIdentifier:#"chatVC"];
self.ticketVC = [ticketStoryboard instantiateViewControllerWithIdentifier:#"ticketVC"];
self.notifVC = [notifStoryboard instantiateViewControllerWithIdentifier:#"notificationVC"];
viewcontrollers = [NSMutableArray new];
[viewcontrollers addObject:self.homeVC];
[viewcontrollers addObject:self.callVC];
[viewcontrollers addObject:self.chatVC];
[viewcontrollers addObject:self.ticketVC];
[viewcontrollers addObject:self.notifVC];
[self.tabButtons[selectedIndex] setSelected:YES];
[self didPressTab:self.tabButtons[selectedIndex]];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)didPressTab:(UIButton *)sender {
selectedIndex = 0;
sender.selected = YES;
NSInteger previousIndex = selectedIndex;
selectedIndex = sender.tag;
[self.tabButtons[previousIndex] setSelected:NO];
UIViewController *previousVC = viewcontrollers[previousIndex];
[previousVC willMoveToParentViewController:nil];
[previousVC.view removeFromSuperview];
[previousVC removeFromParentViewController];
UIViewController *vc = viewcontrollers[selectedIndex];
[self addChildViewController:vc];
vc.view.frame = self.contentView.bounds;
[self.contentView addSubview:vc.view];
[vc didMoveToParentViewController:self];
}
Don't embed 'Tab bar VC' with UINavigationViewController. Embed UINavigationViewController with each of a individual UIViewControllers you added in 'Tab bar VC'.
You should embed all individual view controllers with a navigation controller.
TabBarController > NavigationController > Viewcontroller
For this you need to add a NavigationController for every Controllers like below
-(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
selectedIndex = 0;
UIStoryboard *homeStoryboard = [UIStoryboard storyboardWithName:#"Home" bundle:[NSBundle mainBundle]];
UIStoryboard *callStoryboard = [UIStoryboard storyboardWithName:#"CallPM" bundle:[NSBundle mainBundle]];
UIStoryboard *chatStoryboard = [UIStoryboard storyboardWithName:#"Chat" bundle:[NSBundle mainBundle]];
UIStoryboard *ticketStoryboard = [UIStoryboard storyboardWithName:#"Ticket" bundle:[NSBundle mainBundle]];
UIStoryboard *notifStoryboard = [UIStoryboard storyboardWithName:#"Notification" bundle:[NSBundle mainBundle]];
self.homeVC = [homeStoryboard instantiateViewControllerWithIdentifier:#"homeVC"];
self.callVC = [callStoryboard instantiateViewControllerWithIdentifier:#"callVC"];
self.chatVC = [chatStoryboard instantiateViewControllerWithIdentifier:#"chatVC"];
self.ticketVC = [ticketStoryboard instantiateViewControllerWithIdentifier:#"ticketVC"];
self.notifVC = [notifStoryboard instantiateViewControllerWithIdentifier:#"notificationVC"];
UINavigationController *homeNavController = [[UINavigationController alloc] initWithRootViewController: self.homeVC];
UINavigationController *callVCNavController = [[UINavigationController alloc] initWithRootViewController: self.callVC];
UINavigationController *chatVCNavController = [[UINavigationController alloc] initWithRootViewController: self.chatVC];
UINavigationController *ticketVCNavController = [[UINavigationController alloc] initWithRootViewController: self.ticketVC];
UINavigationController *notifVCNavController = [[UINavigationController alloc] initWithRootViewController: self.notifVC];
viewcontrollers = [NSMutableArray new];
[viewcontrollers addObject: homeNavController];
[viewcontrollers addObject: callVCNavController];
[viewcontrollers addObject:ticketVCNavController];
[viewcontrollers addObject:chatVCNavController];
[viewcontrollers addObject: notifVCNavController];
[self.tabButtons[selectedIndex] setSelected:YES];
[self didPressTab:self.tabButtons[selectedIndex]];
You are using wrong approach. You are embedding tab bar controller in a navigation controller which logically doesn't make any sense.Instead you should embed various navigation controllers into one tab bar controller. Try doing something like this:
Related
I'm trying to pass a NSDictionaryfrom a TableViewControllerto a ViewController. In my TableViewController.m. I have this code to navigate to the ViewController:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *objectDict = [dataArray objectAtIndex:indexPath.row];
NSLog(#"Info: %#", objectDict);
// Pass object to new page
//UIViewController * vc = [[UIViewController alloc] init];
//[self presentViewController:vc animated:YES completion:nil];
SeeInfoVC *controller = [[SeeInfoVC alloc] init];
controller.data = objectDict;
NSString * storyboardName = #"Main";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
UIViewController * vc = [storyboard instantiateViewControllerWithIdentifier:#"SeeInfoVC"];
[self presentViewController:vc animated:YES completion:nil];
In my ViewController.h I have:
#interface SeeCardVC : UIViewController
{
NSDictionary *data;
}
#property (nonatomic, retain)NSDictionary *data;
#end
And then I'm trying to log data in ViewController.m:
#implementation SeeCardVC
#synthesize data;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"Info: %#", data);
}
But it only gives me null :(
What am I doing wrong?
Let's see what your code is doing here:
// Create new controller, assign objectDict to data property
SeeInfoVC *controller = [[SeeInfoVC alloc] init];
controller.data = objectDict;
//Get Storyboard name
NSString * storyboardName = #"Main";
//Get Storyboard (BTW, you can do this with self.storyboard)
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
//Instantiate NEW controller
UIViewController * vc = [storyboard instantiateViewControllerWithIdentifier:#"SeeInfoVC"];
//Present NEW controller
[self presentViewController:vc animated:YES completion:nil];
You created a controller and assigned data to it, and then didn't use it anymore, instead you created a new one from the storyboard, you didn't add the data and presented it.
Basically, you created two, set data to one and presented the other one.
See the problem?
I have a view controller which is my HomeViewController, and I have a modal segue between them.
This is the HomeViewController:
import "HomePageViewController.h"
#import "CreatePageViewController.h"
#import "StackTableViewController.h"
#import "PopUpView.h"
#interface HomePageViewController ()
#property (nonatomic, strong) IBOutlet UIButton *toggleButton;
#property (nonatomic, strong) CreatePageViewController *modalTest;
#property (nonatomic, strong) PopUpView *popup;
#end
#implementation HomePageViewController
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}
-(void)viewDidLoad {
[super viewDidLoad];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:Nil];
_modalTest = [storyboard instantiateViewControllerWithIdentifier:#"ModalTest"];
[_toggleButton addTarget:self action:#selector(go) forControlEvents:UIControlEventTouchUpInside];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(hide) name:#"HideAFPopup" object:nil];
}
-(void)go {
_popup = [PopUpView popupWithView:_modalTest.view];
[_popup show];
}
-(void)hide {
[_popup hide];
}
- (IBAction)pushToNextViewController:(id)sender {
StackTableViewController *vc = [[StackTableViewController alloc]init];
[self presentModalViewController:vc animated:YES];
}
-(void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
I want to add a navigation controller to StackTableViewController...its just a table view and I want it to have a navigation controller, how should I do this?
Also, why xcode tells me my modal method presentModalViewController is deprecated?
tnx
Create a new instance of UINavigationController, with your StackTableViewController as its rootViewController. Then present the navigation controller:
- (IBAction)pushToNextViewController:(id)sender {
StackTableViewController *vc = [[StackTableViewController alloc]init];
UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:vc];
[self presentViewController:navCtrl animated:YES completion:nil];
}
Note that presentModalViewController:animated: is deprecated because it has been replaced by presentViewController:animated:completion:.
I have a Add View where when you tap on Category, the following code is executed
- (void)categoryTapped {
CategoryGroupViewController *categoryGroupViewController = [[CategoryGroupViewController alloc] initWithNibName:#"CategoryGroupViewController" bundle:nil];
[self presentViewController:categoryGroupViewController animated:YES completion:nil];
}
CategoryGroupViewController.h looks like
#interface CategoryGroupViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, strong) UINavigationController *navigationController;
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#end
CategoryGroupViewController.m looks like
#import "CategoryGroupViewController.h"
#import "Helper.h"
static NSString *CellIdentifier = #"Cell";
#interface CategoryGroupViewController ()
#property(nonatomic, strong) NSArray *categories;
#end
#implementation CategoryGroupViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// (todo) should come from API
self.categories = #[#"Food & Drink", #"Utilities"];
}
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CellIdentifier];
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(#"categoryGroup View loaded");
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self];
self.navigationController.title = #"Pick Category";
}
...
}
When I run my application, I see the following in log
2014-11-20 21:29:53.589 myapp-ios[30332:70b] categoryGroup View loaded
But on Simulator, I see
Why don't I see NavigationController?
As you are presenting your CategoryGroupViewController it will not show Navigation Bar by default.
You have to set your CategoryGroupViewController as rootViewController for UINavigationController and instead of presenting CategoryGroupViewController present newly created UINavigationController.
- (void)categoryTapped{
CategoryGroupViewController *categoryGroupVC = [[CategoryGroupViewController alloc] initWithNibName:#"CategoryGroupViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc]initWithRootViewController: categoryGroupVC];
[self presentViewController:categoryGroupViewController animated:YES completion:nil];
}
as i mentioned above if u want a navigaioncontroller u can set CategoryGroupViewController as a root view for a navigation controller and present it for example,
- (void)categoryTapped
{
CategoryGroupViewController *categoryGroupViewController = [[CategoryGroupViewController alloc] initWithNibName:#"CategoryGroupViewController" bundle:nil];
//add this
UINavigationController *navController = [[UINavigationController alloc]initWithRootViewController: categoryGroupViewController];
//present the navigation controller which contains root view controller categoryGroupViewController
[self presentViewController:navController animated:YES completion:nil];
}
You need to instantiate a rootViewController before View did load
[alink]https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html
UIViewController already as a navigationController property, so this is redundant:
// Remove this property from CategoryGroupViewController
#property (nonatomic, strong) UINavigationController *navigationController;
Structuring the user interface in the way you are attempting is also incorrect, and would result in a circular reference between CategoryGroupViewController and UINavigationController. First you need to modify your -viewDidLoad method like so:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(#"categoryGroup View loaded");
// UINavigationController will use this automatically.
self.title = #"Pick Category";
}
Then you should change the way you go about preseting the view controller in your original method:
- (void)categoryTapped {
CategoryGroupViewController *categoryGroupViewController = [[CategoryGroupViewController alloc] initWithNibName:#"CategoryGroupViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:categoryGroupViewController];
[self presentViewController:navController animated:YES completion:nil];
}
Finally, the introduction in the UINavigationController documentation has a great explanation of how the class should be used. Taking a few minutes to read it would help you tremendously in the future.
I have two view controller named ViewController and SecondViewController. From the first view controller i m trying to call my SecondViewController after 5 second. but it will giving me black screen instead of my expected view.
Here is my view controller code,
`
#import "ViewController.h"
#import "SecondViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self performSelector:#selector(loadingNextView) withObject:nil afterDelay:5.0f];
}
-(void)loadingNextView{
SecondViewController *SVC = [[SecondViewController alloc] initWithNibName:nil bundle:nil];
SVC.view.backgroundColor = [UIColor redColor];
[self presentViewController:SVC animated:YES completion:NULL];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end`
Please suggest. If i used button for navigation then its work but my needs is to call automatically on timer.
If your SecondViewController is in storyboard instead of alloc init you have use instantiateViewControllerWithIdentifier
[self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
Dont forget to give the identifier for the controller in the storyboard. So the method will be
-(void)loadingNextView{
[self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
SVC.view.backgroundColor = [UIColor redColor];
[self presentViewController:SVC animated:YES completion:NULL];
}
If you are using storyboard then you cannot initialise the controller with the nib Method "initWithNibName" basically searches for an Xib file, which you do not have as you are using a storyboard, better initialise it in the following way ..
-(void)callNextView{
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:#"yourStoryBoarddName" bundle:nil];
yourViewController *VC = [storyboard instantiateViewControllerWithIdentifier:identifier];
[self presentViewController:VC animated:YES completion:NULL];
}
If you are not using the storyboard, you can simply init the new controller like this
SecondViewController *SVC = [[SecondViewController alloc]init];
[SVC setBackgroundColor: [UIColor redColor]];
[self presentViewController: SVC animated: YES completion: nil];
You need to initialize the controller exact from the storyboard.
- (void)loadingNetView
{
UIStoryboard storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
NSString *identifier = #"SecondController"; // you need to set identifier in storyboard
SecondViewController *controller = [storyboard instantiateViewControllerWithIdentifier:identifier];
}
First of all, sorry for my English.
I'm trying to do an app for iPad with a navigation controller which pushes view controllers when a button "Next" is selected. But I also want to have a popover, called from a button in the nav bar, that allows the user to "jump" from one view controller to another, pushing it with the tableView:didSelectRowAtIndexPath: and the pushViewController:animated: methods, but it's not working.
Summary:
Tab bar -> switches between FirstViewController and SecondViewController (works just fine)
Nav bar (button Next) -> switches between SecondViewController, FirstSlideController and SecondSlideController (it's also good)
Popover -> user selects SecondViewController, FirstSlideController or SecondSlideController (here's the problem!)
Codes:
AppDelegate
UIViewController *viewController1 = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
UINavigationController *navigationController1 = [[UINavigationController alloc] initWithRootViewController:viewController1];
UIViewController *viewController2 = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
UINavigationController *navigationController2 = [[UINavigationController alloc] initWithRootViewController:viewController2];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = #[navigationController1, navigationController2];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
TableViewController(popover)'s didSelectRowAtIndexPath method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == 0){
FirstSlideController *detailViewController = [[FirstSlideController alloc] initWithNibName:#"FirstSlideController" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];
}
else if(indexPath.row == 1){
SecondSlideController *detailViewController = [[SecondSlideController alloc] initWithNibName:#"SecondSlideController" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];
}
else{
SecondViewController *detailViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];
}
}
SecondViewController (with delegate suggested by maros)
-(void) showPopover:(id) sender
{
TableViewController *PopoverView = [[TableViewController alloc] initWithNibName:#"TableViewController" bundle:nil];
self.popOver = [[UIPopoverController alloc] initWithContentViewController:PopoverView];
self.popOver.delegate = self;
[self.popOver presentPopoverFromBarButtonItem:self.navigationItem.leftBarButtonItem permittedArrowDirections: UIPopoverArrowDirectionUp animated: YES];
}
I tried to print self.navigationController and it says it's null. I'd appreciate any help.
Thank you.
Presnented UIPopoverController is not pushed on the navigation stack in the view controller from which it was presented. It is a separate view controller.
Therefore the navigationController inside the popover is nil.
What I would recommend you is to create a delegate MyNavigationPopoverDelegate (the class that creates a popover (PopoverController). Pass it's instance as an delegate to the TableViewController.
After users clicks on some button inside popover, call delegate's method to processes button clicks (myNavigationPopover:(UIPopoverController*)popover clickedButtonAtIndex:(NSInteger)buttonIndex).
Then maybe dismiss delegate?
and finally change navigation however you want! :)
#protocol MyNavigationPopoverDelegate
- (void) myNavigationPopover:(UIPopoverController*)popover clickedButtonAtIndex:(NSInteger)buttonIndex;
#end
#interface TableViewController : UITableVieController // your viewController in popover
... // your code
#property (nonatomic, weak) NSObject <MyNavigationPopoverDelegate> * delegate;
... // your code
#end
#implementation TableViewController
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate myNavigationPopover:self clickedButtonAtIndex:indexPath.row];
}
...
#end
// defines that SecondViewController implements the delegate's method
#interface SecondViewController <MyNavigationPopoverDelegate> : UIViewController
// your code
#end
// code where you presenting popover
#implementation SecondViewController
// This is the method that is executed after your button press and it is responsible for presenting a popover
- (void) presentPopover{
...
myPopover.delegate = self; // setting the delegate
[myPopover presentPopoverFromXXX ...]; // however you present it
...
}
- (void) myNavigationPopover:(UIPopoverController*)popover clickedButtonAtIndex:(NSInteger)buttonIndex
{
UINavigationController *currentNavigationController = ; // get the navigation controller from the tab bar
if(buttonIndex == 0){
FirstSlideController *detailViewController = [[FirstSlideController alloc] initWithNibName:#"FirstSlideController" bundle:nil];
[currentNavigationController pushViewController:detailViewController animated:YES];
}
else if(buttonIndex == 1){
SecondSlideController *detailViewController = [[SecondSlideController alloc] initWithNibName:#"SecondSlideController" bundle:nil];
[currentNavigationController pushViewController:detailViewController animated:YES];
}
else{
SecondViewController *detailViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[currentNavigationController pushViewController:detailViewController animated:YES];
}
}
#end;