How to show the bottom bar when pushed from another view controller ?
Viewcontroller.m
ReminderViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"ReminderViewController"];
[self.navigationController pushViewController:vc animated:YES];
The viewcontroller does not contain any tabbar but ReminderViewController contains tabbar. However, when it was pushed, it did not show the tab bar at the bottom. Am I pushing it wrongly ?
Based on your naming - "ReminderViewController" - it sounds like you are loading and pushing the first view controller in your tab bar controller instead of the tab bar controller itself.
You need to subclass your tab bar controller. It doesn't need any special code... can be as simple as this:
// MyTabBarViewController.h
#import <UIKit/UIKit.h>
#interface MyTabBarViewController : UITabBarController
#end
// MyTabBarViewController.m
#import "MyTabBarViewController.h"
#interface MyTabBarViewController ()
#end
#implementation MyTabBarViewController
#end
Then, load and push your tab bar controller instead of the first tab's view:
MyTabBarViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"MyTabBarViewController"];
[self.navigationController pushViewController:vc animated:YES];
Related
Ok, so i have an interesting situation here:
I have a calendar View, this view does not have a navigation bar, so i created another View to contain the Calendar and added a navigation bar to that view.
So now i have 2 Views displaying a navigation bar and a calendar.
The navigation bars has a butten that is supposed to present a "Insert" controllers, but before it does that, it has to set a #property from the calendar to the "Insert" view controller.
So to sum it up:
Outer View Controller IBAction -> Inner Calendar Set Property on "Insert" -> Inner Calender Present "Insert".
Here is the code:
ViewControllerCalendarContainer.h
#import <UIKit/UIKit.h>
#interface ViewControllerCalendarContainer : UIViewController
- (IBAction)SeguqInsert:(id)sender;
#end
ViewControllerCalendarContainer.m
#import "ViewControllerCalendarContainer.h"
#import "CalendarMonthViewController.h"
...
- (IBAction)SeguqInsert:(id)sender {
CalendarMonthViewController *controller = [[CalendarMonthViewController alloc] initWithNibName:nil bundle:nil];
[controller SegueInsert];
}
CalendarMonthViewController.h
#property (nonatomic, strong) NSDate *dateSelected; // data to send to Insert View Controller
- (void)SegueInsert; // the present "Insert View Controller Method"
CalendarMonthViewController.m
#import "CalendarMonthViewController.h"
#import "ViewControllerInsert.h"
- (void)SegueInsert {
NSDate *dateUserSelected = self.dateSelected;
ViewControllerInsert *controller = [[ViewControllerInsert alloc] initWithNibName:#"ViewControllerInsert" bundle:nil];
controller.dateSelected = dateUserSelected; // set property in Insert
[self presentViewController:controller animated:YES completion:nil]; // present
}
Runtime error on click:
on whose view is not in the window hierarchy!
PS: I cannot Segue via Storyboard, since it uses another instance, and the property that is supposed to get set, does not get set.
Wain is right. The extra view controller is causing a problem. However, I don't think you will be able to just move the code over. You should keep a pointer to your calendar in your navigation controller and just set the property in SequqInsert. Something like this:
#import <UIKit/UIKit.h>
#interface ViewControllerCalendarContainer : UIViewController
#property (weak, nonatomic) CalendarMonthViewController *calendarViewController;
- (IBAction)SeguqInsert:(id)sender;
#end
#import "ViewControllerCalendarContainer.h"
#import "CalendarMonthViewController.h"
...
- (IBAction)SeguqInsert:(id)sender {
NSDate *dateUserSelected = self.dateSelected;
ViewControllerInsert *controller = [[ViewControllerInsert alloc] initWithNibName:#"ViewControllerInsert" bundle:nil];
controller.dateSelected = calendarViewController.dateUserSelected; // set property in Insert
[self presentViewController:controller animated:YES completion:nil]; // present
}
If you're worried about keeping a pointer to the calendar, you can always use protocols to acquire the information.
You seem to have added a view controller that you don't need. The error is because you never show that view controller and then try to present another view controller from it.
Take the code in SegueInsert and move it to SeguqInsert. Then delete the CalendarMonthViewController (which presumably isn't doing anything else and has no other code).
I have an application with UITabBarController as its main controller.
When user taps a button(not in the tab bar, just some other button), I want to add new UIViewController inside my UITabBarController and show it, but I don't want for new UITabBarItem to appear in tab bar. How to achieve such behaviour?
I've tried to set tabBarController.selectedViewController property to a view controller that is not in tabBarController.viewControllers array, but nothing happens. And if I add view controller to tabBarController.viewControllers array new item automatically appears in the tab bar.
Update
Thanks to Levi, I've extended my tab bar controller to handle controllers that not present in .viewControllers.
#interface MainTabBarController : UITabBarController
/**
* By setting this property, tab bar controller will display
* given controller as it was added to the viewControllers and activated
* but icon will not appear in the tab bar.
*/
#property (strong, nonatomic) UIViewController *foreignController;
#end
#import "MainTabBarController.h"
#implementation MainTabBarController
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
self.foreignController = nil;
}
- (void)setForeignController:(UIViewController *)foreignController
{
if (foreignController) {
CGFloat reducedHeight = foreignController.view.frame.size.height - self.tabBar.frame.size.height;
foreignController.view.frame = CGRectMake(0.0f, 0.0f, 320.0f, reducedHeight);
[self addChildViewController:foreignController];
[self.view addSubview:foreignController.view];
} else {
[_foreignController.view removeFromSuperview];
[_foreignController removeFromParentViewController];
}
_foreignController = foreignController;
}
#end
The code will correctly set "foreign" controller's view size and remove it when user choose item in the tab bar.
You either push it (if you have a navigation controller) or add it's view to your visible View Controller's view and add it as child View Controller also.
You can either present the new view controller with:
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion;
Or, if one of your UIViewControllers is inside a UINavigationController, you can:
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
In a non-IUSplitViewController app, I am able to suppress the default back bar animation by adding this to my UIApplicationDelegate class header:
#interface MyNavigationBar : UINavigationBar { } #end
#interface MyNavigationController : UINavigationController { } #end
along with this in the corresponding .m:
#implementation MyNavigationController
- (UIViewController *)popViewControllerAnimated:(BOOL)animated
{
return( [super popViewControllerAnimated:NO] );
}
#end
#implementation MyNavigationBar
- (UINavigationItem *)popNavigationItemAnimated:(BOOL)animated
{
return( [super popNavigationItemAnimated:NO] );
}
#end
Of course I also assigned the Navigation Controller and Navigation Bar objects in MainWindow.xib to MyNavigationController and MyNavigationBar respectively in Interface Builder.
This works like a charm in a standard application.
My problem is achieving the same thing in a UISplitViewController app.
Specifically, I cannot figure out how to override the default behavior of UINavigationBar in that case in order to suppress animation of the navigation bar when a view controller is popped via the back bar button.
I can override the behavior of UINavigationController by doing this whenever I instantiate a UIViewController as the root of the UISplitViewController right pane:
[split is a pointer to my UISplitViewController]
MyNavigationController *nc = (MyNavigationController *) [split.viewControllers objectAtIndex:1];
nc = [[[MyNavigationController alloc] initWithRootViewController:someController] autorelease];
split.viewControllers = [NSArray arrayWithObjects: [split.viewControllers objectAtIndex:0], nc, nil];
split.delegate = someController;
To recap, when I hit the back bar button in my UISplitViewController app, the content area of the active view controller does not animate when popped via the back bar button, but the navigation bar does animate, which looks dopey.
I found the solution for the standard application case in this forum, but saw no mention of a UISplitViewController solution.
I tried overriding initWithCoder in MyNavigationController to assign an instance of MyNavigationBar to the navigationBar attribute, but it wouldn't let me since it is read-only.
Stumped.
I have a view with 3 buttons and a tabbar controller that contains 3 views. I am using the storyboard. I want go from my view to a specific view from the tabbar controller. When I create a segway to the destination view, the tabbar is not included.
The only way I find out is to create a segway to the tabbar controller itself, but then by default the first view is been shown.
Thanks in advance!
Yess!! I got the solution. Do the following:
In you're .h file:
#property (strong, nonatomic) UITabBarController *tabController;
In you're .m file:
#synthesize tabController;
tabController = [self.storyboard instantiateViewControllerWithIdentifier:#"tabbar"];
The selected index is the tab you want to go
tabController.selectedIndex = 1;
[[self navigationController] pushViewController:tabController animated:YES];
When I try to push a UIViewController subclass (MissionViewController) onto a UINavigationController from within my root view controller, the viewDidLoad method is only called if I reference the underlying view after initializing the view controller. However, even with the method called, the screen is not updated.
Both the view controller and the navigation controller are not nil. The file owner in MissionView.xib is set to MissionViewController. The view property of the file owner points to the nib view. I've verified that the topViewController property of the navigation controller points to the MissionViewController object.
If I change MissionViewController to be the root view controller, the view loads fine. Saw several similar posts but still having problems.
rootViewController.h
#interface TreeGraphController : UIViewController
{
MissionViewController *missionViewCtrlr;
}
#property(nonatomic, retain) MissionViewController *missionViewCtrlr;
rootViewController.m
#import "MissionViewController.h"
...
if (!missionViewCtrlr)
{
MissionViewController *ctrlr = [[MissionViewController alloc] initWithNibName:#"MissionView" bundle:nil];
ctrlr.view.hidden = NO;
self.missionViewCtrlr = ctrlr;
[ctrlr release];
}
myAppDelegate *del = [[UIApplication sharedApplication] delegate];
[del.navigationController pushViewController:missionViewCtrlr animated:NO];
What about using
[self.navigationController pushViewController:missionViewCtrlr];
in the rootViewController? I assume rootViewController has been pushed to a UINavigationController and that the navigation controller's view was added as a subview of self.window in the app delegate?
Btw, you may simplify part of your code by just saying
if(!missionViewCtrlr)
self.missionViewCtrlr = [[MisionViewController alloc] init...];