I've got a little problem on navigating through my views.
Here is my configuration :
Ive got 1 Tabbar Controller with 2 relationship segues to 2 simple views embedded inside a navigation controller.
Now i want to navigate from view controller 1 to view controller 3 and i also want to show the correct tab selected inside the tabbar. And if i come from view controller 1, i also want that the back button redirects me the the previous tab. I tried something with a segue connected between that views, but if i do so, it just pushes the view controller onto the navigation stack but not changes the tab. So my question now is, what is the best way of managing this Problem
Screenshot:
Here's a way to do it. But I'm posting this really to illustrate why you shouldn't do it.
I'm using VC2's and VC3's view tag property to pass navigation data around, which has the effect of tightly coupling all three objects.
I override back bar button for the VC1->VC3 context. You lose consistency.
VC3->VC2 provides back animation. VC3->VC1 has no animation as it flips from one tab to another. More inconsistency
VC1->VC3, tap Tab Item 2 transitions to VC2. UI confusion.
Anyway if you still want to do this...
.
ViewController1
Has a "jump to VC3" button, wire up to jumpToVC3:
//ViewController1.m
#import "ViewController1.h"
#implementation ViewController1
- (IBAction)jumpToVC3:(id)sender {
NSArray* viewArray = [[[self.tabBarController viewControllers] objectAtIndex:1] viewControllers];
[[[viewArray lastObject] view] setTag:1];
[self.tabBarController setSelectedIndex:1];
}
#end
"jumptToVC3" switches us to tab 2 and sets the frontmost view's view tag property to 1. IF the frontmost view is VC2, this triggers an immediate segue to VC3. If the frontmost view is VC3, this sets up the back button correctly. If other View Controllers get added to this stack, this navigation will break.
ViewController2
Has a "move to VC3" button, wired to a storyboard segue to VC3 "toVC3"
// ViewController2.m
#import "ViewController2.h"
#import "ViewController3.h"
#implementation ViewController2
//we use the view.tag property as a switch:
//0 = do nothing
//1 = segue to VC3
//2 = go to tab 0
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (self.view.tag ==1){
[self performSegueWithIdentifier:#"toVC3" sender:self];
} else if (self.view.tag == 2){
[self.tabBarController setSelectedIndex:0];
}
self.view.tag = 0;
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (self.view.tag ==1) {
[[segue.destinationViewController view] setTag:1];
} else {
[[segue.destinationViewController view] setTag:0];
}
self.view.tag = 0;
}
- (void) viewWillDisappear:(BOOL)animated
{
self.view.tag = 0;
}
#end
ViewController3
Overrides the back button if it's view.tag is set to 1. If you want both context's back buttons to be consistent, you will need to override for the default behaviour as well. You will not be able to get a standard back button look for this override behaviour.
// ViewController3.m
#import "ViewController3.h"
#implementation ViewController3
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (self.view.tag == 1) {
self.navigationItem.leftBarButtonItem =
[[UIBarButtonItem alloc] initWithTitle:#"0.0"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(goBack:)];
}
self.view.tag = 0;
}
- (IBAction)goBack:(id)sender {
[[[[self.navigationController viewControllers]
objectAtIndex:0] view] setTag:2];
[self.navigationController popToRootViewControllerAnimated:YES];
}
#end
Related
I have two navigation view controllers.When I click on a button in a ViewController that belongs to the second navigation controller i want to dismiss the complete view controller stack of that navigation controller and want to go to a view controller in the first navigation controller.How can I do this? I tried [self.navigationController dismissViewControllerAnimated:YES completion:nil]; and nothing seems to happen.How to do this ?
The bug must be somewhere else. The code you described you are using does indeed work. I created a new project and made an extremely simple example:
#import "ViewController.h"
#interface MyViewController : UIViewController
- (instancetype)initWithColor:(UIColor *)color;
#end
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self presentViewController:[[UINavigationController alloc] initWithRootViewController:[[MyViewController alloc] initWithColor:[UIColor redColor]]] animated:YES completion:nil];
}
#end
#implementation MyViewController
- (instancetype)initWithColor:(UIColor *)color {
if((self = [super init])) {
self.view.backgroundColor = color;
}
return self;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
CGPoint point = [touches.anyObject locationInView:nil];
if(point.x < self.view.frame.size.width*0.5 && point.y < self.view.frame.size.width*0.5) {
[self.navigationController pushViewController:[[MyViewController alloc] initWithColor:self.view.backgroundColor] animated:YES];
} else if(point.x > self.view.frame.size.width*0.5 && point.y < self.view.frame.size.width*0.5) {
[self.navigationController presentViewController:[[UINavigationController alloc] initWithRootViewController:[[MyViewController alloc] initWithColor:[UIColor greenColor]]] animated:YES completion:nil];
} else if(point.x < self.view.frame.size.width*0.5 && point.y > self.view.frame.size.width*0.5) {
[self.navigationController popViewControllerAnimated:true];
} else if(point.x > self.view.frame.size.width*0.5 && point.y > self.view.frame.size.width*0.5) {
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
}
#end
If you copy this into a new project where ViewController is your main view controller a navigation controller will be created and presented on view did appear. The background will be red.
By pressing the top-left part of the screen a new controller of the same color will be pushed to the current top navigation controller.
By pressing top right a new navigation controller will be presented with a green view controller.
By pressing bottom left you may pop the current view controller if any.
And by pressing bottom right you will dismiss the top navigation controller.
So your case is pressing top-left a few times to generate a stack of view controllers on a single navigation controller. Then press top right to present yet another navigation controller (green one). Press a few times on top left to create a stack of few view controllers on a green navigation controller. Now press the bottom right to dismiss the whole green stack and be back to the red navigation controller stack.
Check your code a bit more to see what is going on in your case, why you are experiencing issues in your case. First check if self.navigationController is nil.
try this i think it works for you
self.navigationController?.popToRootViewController(animated: true)
I have a UITabBarController as my root view controller for my app. It has 6 tabs but the app has a custom popup view with 6 buttons used to selected each of the tabs. The tab bar itself is hidden at all times.
The problem is once I try to programmatically select a tab at index 5 or 6 I get an issue. Tabs 1-4 are fine, they get selected in code and the new view controller appears on screen. But since tabs 5 & 6 are technically in the "more" tab, the tab bar appears briefly, shows animation to select the "more" tab and then disappears again. This also puts these "extra" view controllers in a new navigation controller with the "more" table view as the root view controller. This adds a new navigation bar and causes other issues.
Is there any way to do any of the following?
Have more than 5 tabs in a tab bar without the "more" tab.
Disable the "more" tab bar selection animation and the addition of the associated navigation controller.
Create a simple custom controller that could replace the UITabBarController entirely.
It seems like there are a lot of situations where one would want to show more than 5 tabs and yet hide the tab bar but I couldn't find anyone discussing this issue.
According to your requirements, I think you need a custom tabar controller.
This project may help you:
RDVTabBarController
Besides, I must warn you that using custom tabbar controller you may lost the chances to use the convenient features that system tabber contrller provides.
You should use the custom tabbar controller only if the system tabbar controler doesn't fit you needs.
Try the code below . The ViewController used here is a sub class of UITabBarController. In the .h file add ITabBarDelegate , UITabBarControllerDelegate.I guess this way you can add 6 tabs. I have done two tabs here and transition with animation. Use the delegate method
(BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
as shown below to apply animations.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
fvcontroller = [self.storyboard instantiateViewControllerWithIdentifier:#"navcontroller"];
svcontroller = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
NSMutableArray *viewcontrollers = [[NSMutableArray alloc]init];
[viewcontrollers addObject:fvcontroller];
[viewcontrollers addObject:svcontroller];
[self setViewControllers:viewcontrollers];
fvcontroller.tabBarItem = [[UITabBarItem alloc]initWithTitle:#"Me" image:[UIImage imageNamed:#"me.png"] tag:1];
svcontroller.tabBarItem = [[UITabBarItem alloc]initWithTitle:#"Chat" image:[UIImage imageNamed:#"chat3.png"] tag:2];
// _tbbar.delegate = self;
self.delegate = self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
UIView *from = self.selectedViewController.view;
UIView *to = viewController.view;
NSInteger fromindex = [self.viewControllers indexOfObject:self.selectedViewController];
NSInteger toindex = [self.viewControllers indexOfObject:viewController];
[UIView transitionFromView:from
toView:to
duration:.5
options:UIViewAnimationOptionTransitionFlipFromBottom
completion:^(BOOL finished) {
if (finished) {
tabBarController.selectedIndex = toindex;
}
}];
//(toindex > fromindex ? UIViewAnimationOptionTransitionCurlUp : UIViewAnimationOptionTransitionCurlDown)
return NO;
}
#end
Due to a weird request which I tried to turn down but it didn't work, I had to override the navigationBar's back Button.
I have made a custom UINavigationController subclass and hacked the
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item method.
Here is my code:
#interface CustomUINavigationController ()
#end
#implementation CustomUINavigationController
#pragma mark - UINavigationBar delegate methods
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
if ([[self.viewControllers lastObject] isKindOfClass:[ViewController1 class]]) {
ViewController1 *vc1 = (ViewController1 *)[self.viewControllers lastObject];
[vc1 handleBackAction];
if (vc1.canPopVC == YES) {
[self popViewControllerAnimated:YES];
return YES;
} else {
return NO;
}
}
[self popViewControllerAnimated:YES];
return YES;
}
#end
All works fine, except when I pop a viewController programmatically. The app crashed every time when I wanted to perform a push after said pop. Turning NSZombie on, revealed that when popping a viewController programmatically, its parent viewController is deallocated.
At this point, making a custom backButton is not a option since it will lose the native iOS 7 swipe to popViewController feature.
Crash log:
*** -[ContactsDetailViewController performSelector:withObject:withObject:]: message sent to deallocated instance 0x1806b790
(My previous post was completely wrong. This is a complete rewrite with an appropriate solution.)
I had this behavior pop up when I chose to delete some code generating a warning when I was converting to ARC -- code that I thought was not being called.
Here's the situation:
If you shadow navigationBar:shouldPopItem: in a subclass of UINavigationController, then the current view controller will NOT be popped when the user touches the NavBar's BACK button. However, if you call popViewControllerAnimated: directly, your navigationBar:shouldPopItem: will still be called, and the view controller will pop.
Here's why the view controller fails to pop when the user touches the BACK button:
UINavigationController has a hidden method called navigationBar:shouldPopItem:. This method IS called when the user clicks the BACK button, and it is the method that normally calls popViewControllerAnimated: when the user touches the BACK button.
When you shadow navigationBar:shouldPopItem:, the super class' implementation is not called, and hence the ViewController is not popped.
Why you should NOT call popViewControllerAnimated: within your subclass' navigationBar:shouldPopItem::
If you call popViewControllerAnimated: within navigationBar:shouldPopItem:, you will see the behavior that you desire when you click the BACK button on the NavBar: You can determine whether or not you want to pop, and your view controller pops if you want it to.
But, if you call popViewControllerAnimated: directly, you will end up popping two view controllers: One from your direct call to popViewControllerAnimated:, and one from the call you added to within navigationBar:shouldPopItem:.
What I believe to be the safe solution:
Your custom nav controller should be declared like this:
#interface CustomNavigationController : UINavigationController <UINavigationBarDelegate>
{
// .. any ivars you want
}
#end
Your implementation should contain code that looks something like this:
// Required to prevent a warning for the call [super navigationBar:navigationBar shouldPopItem:item]
#interface UINavigationController () <UINavigationBarDelegate>
#end
#implementation CustomNavigationController
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
BOOL rv = TRUE;
if ( /* some condition to determine should NOT pop */ )
{
// we won't pop
rv = FALSE;
// extra code you might want to execute ...
} else
{
// It's not documented that the super implements this method, so we're being safe
if ([[CustomNavigationController superclass]
instancesRespondToSelector:#selector(navigationBar:shouldPopItem:)])
{
// Allow the super class to do its thing, which includes popping the view controller
rv = [super navigationBar:navigationBar shouldPopItem:item];
}
}
return rv;
}
I'm not 100% certain but I don't think you should actually be popping the view controller in that delegate method.
"should" delegate methods don't normally do something. They just assert whether something should or shouldn't be done.
Change your method to this...
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
if ([[self.viewControllers lastObject] isKindOfClass:[ViewController1 class]]) {
ViewController1 *vc1 = (ViewController1 *)[self.viewControllers lastObject];
[vc1 handleBackAction];
if (vc1.canPopVC == YES) {
return YES;
} else {
return NO;
}
}
return YES;
}
And see if it works.
All I have done is removed the popViewController calls.
EDIT - How to add a custom back button
In a category on UIBarButtonItem...
+ (UIBarButtonItem *)customBackButtonWithTarget:(id)target action:(#SEL)action
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundImage:[UIImage imageNamed:#"Some image"] forState:UIControlStateNormal];
[button setTitle:#"Some Title" forState:UIControlStateNormal];
[button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithCustomView:button];
return barButtonItem;
}
Now whenever you want to set a custom back button just use...
UIBarButtonItem *backButton = [UIBarButtonItem customBackButtonWithTarget:self action:#selector(backButtonPressed)];
I would suggest a completely different approach.
Create a base class for the view controllers that you are pushing on the navigation stack. In the viewDidLoad method set your custom button as the leftBarButtonItem of the navigationItem and add a -backAction: which invokes the popViewControllerAnimated: method of the navigation controller.
That way you won't care about things like losing functionality of UINavigationController like the swipe to pop and you won't have to override the navigationBar:shouldPopItem: method at all.
You probably need to do [super shouldPop... instead of actual [self popViewControllerAnimated:YES];.
The reason being that the way UINavigationController implements stack is private, so you should mess with the method calls as little as possible.
Anyway, this looks like a hack. Moreover, the user will have no visual clue that you are blocking the navigation action. What's wrong with disabling the button via:
self.navigationController.navigationItem.backBarButtonItem.enabled = NO;
It's my fix to #henryaz answer for Xcode 11:
#interface UINavigationControllerAndNavigationBarDelegate : UINavigationController<UINavigationBarDelegate>
#end
#interface CustomNavigationController : UINavigationControllerAndNavigationBarDelegate
#end
// changed this method just a bit
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
BOOL shouldPop = // detect if need to pop
if (shouldPop) {
shouldPop = [super navigationBar:navigationBar shouldPopItem:item]; // before my fix this code failed with compile error
}
return shouldPop;
}
I am trying to implement a push-up UINavigationBar, where the position of the navigation bar is attached to the contentOffset of the UIScrollView (similar to how safari works in ios7).
In order to get the dynamic movement working I am using a UINavigationBar created programatically and added as a subview of the UIViewController's view (it is accessible as self.navbar).
The UIViewController is within a UINavigationController hierarchy, so I am hiding the built-in self.navigationController.navigationBar at the top of -viewWillAppear:.
The problem I am trying to solve is to add a back button to this new standalone navbar. I would preferably like to simply copy the buttons or even the navigationItems from the navigationController and its hidden built-in navbar, but this doesnt seem to work
Is my only solution to set leftBarButtonItem on my standalone navbar to be a fake back button (when there is a backItem in the navController's navbar)? This seems a bit hacky, and I'd rather use the built backButton functionality.
Another way to do that, once you have your own UINavigationBar set, is to push two UINavigationItems on your navigationBar, causing back button to appear. You can then customize what happens when the back button is pressed.
Here's how I did that
1 - Some UINavigationItem subclass, to define extra-behavior / customization parameters
#interface MyNavigationItem : UINavigationItem
//example : some custom back action when 'back' is pressed
#property (nonatomic, copy) void (^onBackClickedAction)(void);
#end
2 - Then wire that into your UINavigationBarDelegate :
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
if ([item isKindOfClass:[MyNavigationItem class]]) {
MyNavigationItem *navItem = (MyNavigationItem *)item;
//custom action
if (navItem.backAction) {
navItem.backAction();
}
return YES;// return NO if you don't want your bar to animate to previous item
} else {
return YES;
}
}
You could adapt that scheme, calling your UINavigationController pop method on back action.
This is still hacky
Vinzzz' answer was a good solution. Here is my implementation, as the context was slightly different.
In the UIViewController's viewDidLoad method I setup my navbar's navigation items like this:
NSMutableArray* navItems = [#[] mutableCopy];
if (self.navigationController.viewControllers.count > 1)
{
NSInteger penultimateIndex = (NSInteger)self.navigationController.viewControllers.count - 2;
UIViewController* prevVC = (penultimateIndex >= 0) ? self.navigationController.viewControllers[penultimateIndex] : nil;
UINavigationItem* prevNavItem = [[UINavigationItem alloc] init];
prevNavItem.title = prevVC.title;
[navItems addObject:prevNavItem];
}
UINavigationItem* currNavItem = [[UINavigationItem alloc] init];
... <Add any other left/right buttons to the currNavItem> ...
[navItems addObject:currNavItem];
[self.navbar setItems:navItems];
...where self.navbar is my floating stand-alone UINavigationBar.
I also assign the current view controller to be self.navbar's delegate, and then listen for the -navigationBar:shouldPopItem: event that is triggered when the back button is pressed:
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
if (navigationBar == self.navbar)
{
[self.navigationController popViewControllerAnimated:YES];
return NO;
}
return YES;
}
(If you return YES, it will crash when a swipe gesture is used in ios7).
I'm trying to make a form that spans three tabs. You can see in the screenshot below where the tabs will be. When the user taps a tab, the Container View should update and show a particular view controller I have.
Tab 1 = View Controller 1
Tab 2 = View Controller 2
Tab 3 = View Controller 3
The view controller shown above has the class PPAddEntryViewController.m. I created an outlet for the Container view within this class and now have a Container View property:
#property (weak, nonatomic) IBOutlet UIView *container;
I also have my IBActions for my tabs ready:
- (IBAction)tab1:(id)sender {
//...
}
- (IBAction)tab2:(id)sender {
//...
}
- (IBAction)tab3:(id)sender {
//...
}
How do I set the container in those IBActions to change the view controller that the Container View holds?
Among a few other things, here's what I've tried:
UIViewController *viewController1 = [self.storyboard instantiateViewControllerWithIdentifier:#"vc1"];
_container.view = viewController1;
...but it doesn't work. Thanks in advance.
Switching using Storyboard, Auto-layout or not, a Button of some sort, and a series of Child View Controllers
You want to add the container view to your view and when the buttons that 'switch' child view controllers are pressed fire off the appropriate segue and perform the correct setup work.
In the Storyboard you can only connect one Embed Segue to the Container View. So you create an intermediate handling controller. Make the embed segue and give it an identifier, for example EmbededSegueIdentifier.
In your parent view controller wire up the button or whatever you want and keep are reference to your child view controller in the prepare segue. As soon as the parent view controller loads the segue will be fired.
The Parent View Controller
#property (weak, nonatomic) MyContainerViewController *myContainerViewController;
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"EmbeddedSegueIdentifier"]) {
self.myContainerViewController = segue.destinationViewController;
}
}
It should be fairly easy for you to delegate to your container controller the button presses.
The Container Controller
This next bit of code was partly borrowed from a couple of sources, but the key change is that auto layout is being used as opposed to explicit frames. There is nothing preventing you from simply changing out the lines [self addConstraintsForViewController:] for viewController.view.frame = self.view.bounds. In the Storyboard this Container View Controller doesn't do anything more that segue to the destination child view controllers.
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%s", __PRETTY_FUNCTION__);
[self performSegueWithIdentifier:#"FirstViewControllerSegue" sender:nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *destinationViewController = segue.destinationViewController;
if ([self.childViewControllers count] > 0) {
UIViewController *fromViewController = [self.childViewControllers firstObject];
[self swapFromViewController:fromViewController toViewController:destinationViewController];
} else {
[self initializeChildViewController:destinationViewController];
}
}
- (void)initializeChildViewController:(UIViewController *)viewController
{
[self addChildViewController:viewController];
[self.view addSubview:viewController.view];
[self addConstraintsForViewController:viewController];
[viewController didMoveToParentViewController:self];
}
- (void)swapFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController
{
[fromViewController willMoveToParentViewController:nil];
[self addChildViewController:toViewController];
[self transitionFromViewController:fromViewController toViewController:toViewController duration:0.2f options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:^(BOOL finished) {
[self addConstraintsForViewController:toViewController];
[fromViewController removeFromParentViewController];
[toViewController didMoveToParentViewController:self];
}];
}
- (void)addConstraintsForViewController:(UIViewController *)viewController
{
UIView *containerView = self.view;
UIView *childView = viewController.view;
[childView setTranslatesAutoresizingMaskIntoConstraints:NO];
[containerView addSubview:childView];
NSDictionary *views = NSDictionaryOfVariableBindings(childView);
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[childView]|"
options:0
metrics:nil
views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[childView]|"
options:0
metrics:nil
views:views]];
}
#pragma mark - Setters
- (void)setSelectedControl:(ViewControllerSelectionType)selectedControl
{
_selectedControl = selectedControl;
switch (self.selectedControl) {
case kFirstViewController:
[self performSegueWithIdentifier:#"FirstViewControllerSegue" sender:nil];
break;
case kSecondViewController:
[self performSegueWithIdentifier:#"SecondViewControllerSegue" sender:nil];
break;
default:
break;
}
}
The Custom Segues
The last thing you need is a custom segue that does nothing, going to each destination with the appropriate segue identifier that is called from the Container View Controller. If you don't put in an empty perform method the app will crash. Normally you could do some custom transition animation here.
#implementation SHCDummySegue
#interface SHCDummySegue : UIStoryboardSegue
#end
- (void)perform
{
// This space intentionally left blank
}
#end
I recently found the perfect sample code for what I was trying to do. It includes the Storyboard implementation and all the relevant segues and code. It was really helpful.
https://github.com/mhaddl/MHCustomTabBarController
Update: UITabBarController is the recommended way to go, as you found out earlier. In case you'd like to have a custom height, here is a good start: My way of customizing UITabBarController's tabbar - Stackoverflow answer
As of iOS 5+ you have access to customize the appearance via this API; UIAppearance Protocol Reference. Here is a nice tutorial for that: How To Customize Tab Bar Background and Appearance
The most obvious way to achieve what you're looking for is to simply manage 3 different containers (they are simple UIViews) and implement each of them to hold whatever content view you need for each tab (use the hidden property of the containers).
Here is an example of what's possible to achieve with different containers:
These containers "swapping" can be animated of course. About your self-answer, you probably chose the right way to do it.
have a member variable to hold the viewController:
UIViewController *selectedViewController;
now in the IBActions, switch that AND the view. e.g.
- (IBAction)tab1:(id)sender {
UIViewController *viewController1 = [self.storyboard instantiateViewControllerWithIdentifier:#"vc1"];
_container.view = viewController1.view;
selectedViewController = viewController1;
}
to fire view did appear and stuff call removeChildViewController, didMoveToParent, addChildViewController, didMoveToParent
I got this to work by using a UITabBarController. In order to use custom tabs, I had to subclass the TabBarController and add the buttons to the controller in code. I then listen for tap events on the buttons and set the selectedIndex for each tab.
It was pretty straight forward, but it's a lot of junk in my Storyboard for something as simple as 3 tabs.