I am following Apress Beginning IOS 6 for school where we were asked by the professor to implement a custom algorithm that switches between 3 views (blue, yellow, and green) with each press of the "Next View" button in the toolbar. My approach was to add the subviews at different indices and shuffle the views in the hierarchy in BIDSwitchViewController.m:
#import "BIDSwitchViewController.h"
#import "BIDYellowViewController.h"
#import "BIDBlueViewController.h"
#import "BIDGreenViewController.h"
NSInteger count;
#interface BIDSwitchViewController ()
#end
#implementation BIDSwitchViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
self.yellowViewController = [[BIDYellowViewController alloc] initWithNibName:#"YellowView"
bundle:nil];
self.greenViewController = [[BIDGreenViewController alloc] initWithNibName:#"GreenView"
bundle:nil];
self.blueViewController = [[BIDBlueViewController alloc] initWithNibName:#"BlueView"
bundle:nil];
//the topmost view is the last one in the stack (2)
[self.view insertSubview:self.blueViewController.view atIndex:2];
[self.view insertSubview:self.yellowViewController.view atIndex:1];
[self.view insertSubview:self.greenViewController.view atIndex:0];
[self.view setBackgroundColor:self.blueViewController.view.backgroundColor];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.blueViewController = [[BIDBlueViewController alloc]
initWithNibName:#"BlueView" bundle:nil];
[self.view insertSubview:self.blueViewController.view atIndex:0];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.;
self.blueViewController = nil;
self.yellowViewController = nil;
self.greenViewController = nil;
}
- (IBAction)switchViews:(id)sender
{
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:
UIViewAnimationTransitionFlipFromRight
forView:self.view cache:YES];
switch (count)
{
case 0:
[self.view sendSubviewToBack:self.blueViewController.view];
[self.view bringSubviewToFront:self.yellowViewController.view];
[self.view setBackgroundColor:self.yellowViewController.view.backgroundColor];
break;
case 1:
[self.view sendSubviewToBack:self.yellowViewController.view];
[self.view bringSubviewToFront:self.greenViewController.view];
[self.view setBackgroundColor:self.greenViewController.view.backgroundColor];
break;
case 2:
[self.view sendSubviewToBack:self.greenViewController.view];
[self.view bringSubviewToFront:self.blueViewController.view];
[self.view setBackgroundColor:self.blueViewController.view.backgroundColor];
break;
}
if (++count >= 3)
{
count = 0;
}
[UIView commitAnimations];
}
#end
Here is the code in BIDAppDelegate.m where the root view controller is added as an instance of BIDSwitchViewController:
#implementation BIDAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.switchViewController = [[BIDSwitchViewController alloc]
initWithNibName:#"SwitchView" bundle:nil];
UIView *switchView = self.switchViewController.view;
CGRect switchViewFrame = switchView.frame;
switchViewFrame.origin.y += [UIApplication
sharedApplication].statusBarFrame.size.height;
switchView.frame = switchViewFrame;
//[self.window addSubview:switchView];
self.window.rootViewController = self.switchViewController;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
And the BIDSwitchViewController.h header file:
#import <UIKit/UIKit.h>
#class BIDSwitchViewController;
#interface BIDAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) BIDSwitchViewController *switchViewController;
#end
The app and logic all work as the views switch from blue -> yellow -> green and back to blue again. As shown in the first picture (BIDBlueViewController's BlueView.xib subview of the BIDSubViewController) each of the views overlap the toolbar slightly. I have double and triple checked all of my simulated metrics in IB with the help of one of my classmates:
Am I using poor practice in shuffling the topmost views through the view hierarchy array, instead of removing each view via the book's method of "removeFromParentViewController()," or is their another, hidden cause for the sub views not properly sitting inside / behind the parent view?
Your UIToolbar control's Z-Order on it's view is behind your blue view controller. Since you created it in IB, you can add an IBOutlet for it, and bring it's view to top of the parent view. You're loading the ViewControllers as subviews, so they are all subviews of self.view of your parent.
In your header definition:
IBOutlet *toolBar UIToolbar;
Bring to front in your implementation.
[self.view bringSubviewToFront:toolBar];
You can do this after you've added the blue controller subview or at the end of all your case statements.
Related
I have a view like this:
#interface MyView ()
#property (nonatomic, strong) UIView* subView;
#end
#implementation MyView
#pragma mark - init && dealloc
-(instancetype)init
{
self = [super init];
if (self){
[self setupSubView];
[self setupAutoLayoutSubView];
}
return self;
}
#pragma mark - setup
-(void)setupSubView
{
_subView = [UIView newAutoLayoutView];
[self addSubview:_subView];
}
-(void)setupAutoLayoutSubView
{
// autolayout: to centralize the subView
// if you don't use PureLayout, you can use the traditional way
[_subView autoCenterInSuperview];
}
#end
When I add this view into Window, the reference counting on this view will be increased to 3.
MyView* v = [[MyView alloc] init];
NSLog(#"reference counting = %ld",CFGetRetainCount((CFTypeRef)v)); //- 1
UIWindow* window = [[UIApplication sharedApplication] keyWindow];
[window addSubView:v];
NSLog(#"reference counting = %ld",CFGetRetainCount((CFTypeRef)v)); //- 3 INCORRECT
The strange thing is if I comment the "autolayout" part from method: "setupAutoLayoutSubView", the reference counting is correct ( = 2 )
or if I add my view to a normal view, the reference counting is correct as well
MyView* v = [[MyView alloc] init];
NSLog(#"reference counting = %ld",CFGetRetainCount((CFTypeRef)v)); //- 1
UIView* normalView = [[UIView alloc] init];
[normalView addSubView:v];
NSLog(#"reference counting = %ld",CFGetRetainCount((CFTypeRef)v)); //- 2 : CORRECT
How would one present a UIViewController (from Storyboard say) that is modal, and slides up from the bottom of the presenting view controller. Requirements would be:
slides up from bottom, with widths aligning with the width of the presenting view controller
does NOT take up whole screen or whole parent presenting view controller (rather only is as high as required to show itself)
can be shown within the context of a view controller which doesn't take the whole screen
I do not use storyboards so I wrote it all out. You can copy paste this into a brand new project and run it to see it working.
Your PresentingController needs to conform to two things. The first protocol is: UIViewControllerTransitioningDelegate which allows the controller to provide a custom presenter (namely itself in our case below). Whatever you return here (be it self, or some other object) needs to conform to UIViewControllerAnimatedTransitioning and provide the custom animations. For this self-contained example, I chose the current viewController to be the presenter and animator.
Next, it needs to conform to protocol: UIViewControllerAnimatedTransitioning which provides the custom animation for any presenting or dismissing controllers.
In other words, when we present or dismiss a viewController, animateTransition from the UIViewControllerAnimatedTransitioning protocol will be called to determine how the child controller should animate into perspective or dismiss from the view-port.
Example (With Transition Animation):
//
// ViewController.m
// SO
//
// Created by Brandon T on 2017-01-23.
// Copyright © 2017 XIO. All rights reserved.
//
#import "ViewController.h"
//Some view controller that will be presented modally.
//I have coloured it red.
#interface ModalController : UIViewController
#end
#implementation ModalController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor redColor];
}
#end
//The view controller that will present or dismiss some other view controller modally.
//I have coloured it white.
#interface ViewController () <UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning>
#property (nonatomic, assign) bool presentingModalController;
#property (nonnull, nonatomic, strong) ModalController *modalController;
#property (nonnull, nonatomic, strong) UIButton *button;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
//For this example, I add a button to present and dismiss the redViewController.
self.button = [[UIButton alloc] initWithFrame:CGRectMake(15, self.view.center.y - 100, self.view.frame.size.width - 30, 45)];
[self.button setTitle:#"Present" forState:UIControlStateNormal];
[self.button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self.button setBackgroundColor:[UIColor lightGrayColor]];
[self.button.layer setCornerRadius:5.0];
[self.button addTarget:self action:#selector(onButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.button];
//Create the redViewController and set its transitioning delegate to self (this controller will be providing the animation and presenter).
//We also set the style to OverFullScreen because we don't want this controller to disappear.
//When a view controller is presented, the one that presented it usually disappears or gets removed from the hierarchy until the child is dismissed. In the case of alerts, or controllers that need to display OVER the current one, we need to set the modalPresentationStyle.
self.modalController = [[ModalController alloc] init];
self.modalController.transitioningDelegate = self;
self.modalController.modalPresentationStyle = UIModalPresentationOverFullScreen;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)onButtonClicked:(UIButton *)button {
if (self.modalController.view.window == nil) {
[self presentViewController:self.modalController animated:YES completion:nil];
[self.button setTitle:#"Dismiss" forState:UIControlStateNormal];
//not a good idea but meh.. I need to keep this example short.
[self.view.window addSubview:self.button];
}
else {
[self.modalController dismissViewControllerAnimated:YES completion:nil];
[self.button setTitle:#"Present" forState:UIControlStateNormal];
[self.view addSubview:self.button];
}
}
//Custom Animations and Presenters.
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
self.presentingModalController = true; //We are presenting the controller.
return self; //Who is animating it? We are.
}
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
self.presentingModalController = false; //We are dismissing the view controller.
return self; //Who animated it? We did.
}
//How fast should it present? I chose 0.5 seconds.
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext {
return 0.5;
}
//The actual animation code.
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
if (self.presentingModalController) {
//If we are presenting, we need to add the new controller's view as a sub-view.
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
//We need a starting frame for the animation.
CGRect startingFrame = transitionContext.containerView.bounds;
startingFrame.origin.y = startingFrame.size.height; //Starts from the bottom of the parent.
startingFrame.size.height = 100; //Has a height of 100.
//We need an end frame for the animation.
CGRect finalFrame = transitionContext.containerView.bounds;
finalFrame.origin.y = finalFrame.size.height - 100; //100 from the bottom of the parent.
finalFrame.size.height = 100; //Present with a size of 100 height.
//Add the controller's view as a subview of the context.
[transitionContext.containerView addSubview:toViewController.view];
[toViewController.view setFrame:startingFrame];
//Start animating from "startFrame" --> "endFrame" with 0.5 seconds duration and no delay. I chose easeIn style.
[UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
[toViewController.view setFrame:finalFrame];
} completion:^(BOOL finished) {
//We are finished animating, complete the transition!
[transitionContext completeTransition:YES];
}];
}
else {
//If we are dismissing the view controller, we need to animate it down the screen and then remove its view from the context.
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
//We only need one frame. This is the first frame. We are animating from "endFrame" --> "startingFrame" (backwards/reverse animation).
CGRect startingFrame = transitionContext.containerView.bounds;
startingFrame.origin.y = startingFrame.size.height; //Starts from the bottom of the parent.
startingFrame.size.height = 100; //Has a height of 100.
//Start the animation with 0.5 seconds duration and I chose easeOut style.
[UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[fromViewController.view setFrame:startingFrame];
} completion:^(BOOL finished) {
//Remove the view controller's view from the context and complete the transition!
[fromViewController.view removeFromSuperview];
[transitionContext completeTransition:YES];
}];
}
}
#end
Example (Without Transition Animation):
//
// ViewController.m
// SO2
//
// Created by Brandon Thomas on 2017-01-23.
// Copyright © 2017 XIO. All rights reserved.
//
#import "ViewController.h"
#interface ModalController : UIViewController
#end
#implementation ModalController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor redColor];
}
#end
#interface ViewController ()
#property (nonatomic, assign) bool presentingModalController;
#property (nonnull, nonatomic, strong) ModalController *modalController;
#property (nonnull, nonatomic, strong) UIButton *button;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.button = [[UIButton alloc] initWithFrame:CGRectMake(15, self.view.center.y - 100, self.view.frame.size.width - 30, 45)];
[self.button setTitle:#"Present" forState:UIControlStateNormal];
[self.button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self.button setBackgroundColor:[UIColor lightGrayColor]];
[self.button.layer setCornerRadius:5.0];
[self.button addTarget:self action:#selector(onButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.button];
self.modalController = [[ModalController alloc] init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)onButtonClicked:(UIButton *)button {
if (self.modalController.view.window == nil) {
//Present
CGRect startingFrame = self.view.bounds;
startingFrame.origin.y = startingFrame.size.height; //Starts from the bottom of the parent.
startingFrame.size.height = 100; //Has a height of 100.
CGRect finalFrame = self.view.bounds;
finalFrame.origin.y = finalFrame.size.height - 100; //100 from the bottom of the parent.
finalFrame.size.height = 100; //Present with a size of 100 height.
[self.modalController.view setFrame:startingFrame];
[self.modalController willMoveToParentViewController:self];
[self addChildViewController:self.modalController];
[self.view addSubview:self.modalController.view];
[self.modalController didMoveToParentViewController:self];
[UIView animateWithDuration:0.5 animations:^{
[self.modalController.view setFrame:finalFrame];
} completion:^(BOOL finished) {
}];
}
else {
//Dismiss
CGRect startingFrame = self.view.bounds;
startingFrame.origin.y = startingFrame.size.height; //Starts from the bottom of the parent.
startingFrame.size.height = 100; //Has a height of 100.
[UIView animateWithDuration:0.5 animations:^{
[self.modalController.view setFrame:startingFrame];
} completion:^(BOOL finished) {
[self.modalController.view removeFromSuperview];
[self.modalController willMoveToParentViewController:nil];
[self.modalController removeFromParentViewController];
[self.modalController didMoveToParentViewController:nil];
}];
}
}
#end
Check out the Apple documentation for this:
Presenting a View Controller Using Custom Animations
To present a view controller using custom animations, do the following
in an action method of your existing view controllers:
Create the view controller that you want to present. Create your
custom transitioning delegate object and assign it to the view
controller’s transitioningDelegate property. The methods of your
transitioning delegate should create and return your custom animator
objects when asked. Call the
presentViewController:animated:completion: method to present the view
controller. When you call the
presentViewController:animated:completion: method, UIKit initiates the
presentation process. Presentations start during the next run loop
iteration and continue until your custom animator calls the
completeTransition: method. Interactive transitions allow you to
process touch events while the transition is ongoing, but
noninteractive transitions run for the duration specified by the
animator object.
EDIT:
Your alternative option is to create a container with your custom sizes and animate your UIViewController added as a child view of your UIViewController:
[self addChildViewController:content];
content.view.frame = [self frameForContentController];
[self.view addSubview:self.currentClientView];
[content didMoveToParentViewController:self];
Taken from this Thread
I'm trying to position a button so that it is always an X amount of pixels from the bottom of the screen. The view is laid out programmatically using auto layout. If I use: #"V:|-44-[closeModalButton]" the object aligns 44 pixels from the top of the screen as expected. However, #"V:[closeModalButton]-44-|" causes the button to never show up. It seems like it ought to be pretty straightforward, so I feel like I'm missing something really obvious.
Implementation of view
#import "DetailView.h"
#implementation DetailView
#synthesize closeModalButton;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor = [UIColor whiteColor];
CGRect aFrame = [[UIScreen mainScreen] bounds];
self.frame = aFrame;
closeModalButton = [UIButton buttonWithType:UIButtonTypeCustom];
[closeModalButton setImage: [UIImage imageNamed:#"closeButton.png"] forState:UIControlStateNormal];
[closeModalButton setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:closeModalButton];
NSDictionary *viewArranging = NSDictionaryOfVariableBindings(closeModalButton);
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[closeModalButton(44)]-44-|"
options:0
metrics:0
views:viewArranging]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-149-[closeModalButton(44)]-149-|"
options:0
metrics:0
views:viewArranging]];
}
return self;
}
#end
View controller
#import "DetailViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
{
DetailView *_detailView;
}
- (void)loadView
{
_detailView = [[DetailView alloc] init];
[self setView:_detailView];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[_detailView.closeModalButton addTarget:self
action:#selector(closeModalButtonPressed:)
forControlEvents:UIControlEventTouchUpInside];
}
- (void)closeModalButtonPressed:(UIButton *)sender{
[self dismissViewControllerAnimated:YES
completion:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Ok, so it looks like DetailView.h subclassed UIScrollView rather than UIView. Setting the proper subclass caused the constraints to operate as expected.
I have 2 view controllers, the first is a storyboard (this is root) and the second with is nibless. When I press a button in the root view controller it should call the second controller.
Here the code for my second view controller:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
UILabel *sampleLabel = [[UILabel alloc] initWithFrame: CGRectMake(0,0,100,100)];
UIImageView * basketItem = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"B.jpg"]];
[self.view addSubview:sampleLabel];
[self.view addSubview:basketItem];
NSLog(#"%#",self.view.subviews);
sampleLabel.text = #"Main Menu";
}
return self;
}
self.view.sebviews query shows that 2 objects label and imageView objects exists, but in fact I see black screen only.
Here is transition method
- (void)transitionToViewController:(UIViewController *)aViewController
withOptions:(UIViewAnimationOptions)options
{
aViewController.view.frame = self.containerView.bounds;
[UIView transitionWithView:self.containerView
duration:0.65f
options:options
animations:^{
[self.viewController.view removeFromSuperview];
[self.containerView addSubview:aViewController.view];
}
completion:^(BOOL finished){
self.viewController = aViewController;
}];
}
Move the code in viewDidLoad. Here you are sure the view has been loaded into memory and hence can be further customized.
- (void)viewDidLoad
{
[super viewDidLoad];
UILabel *sampleLabel = [[UILabel alloc] initWithFrame: CGRectMake(0,100,100,100)];
UIImageView * basketItem = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"B.jpg"]];
[self.view addSubview:sampleLabel];
[self.view addSubview:basketItem];
NSLog(#"%#",self.view.subviews);
sampleLabel.text = #"Main Menu";
}
If you are not using ARC, pay attention to memory leaks.
Note
I really suggest to read Apple doc for this. You should understand how things work. Hope that helps.
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html
Edit
I don't know what the problem could be. To make it work, try to override loadView (in MenuViewController) method like the following:
- (void)loadView
{
CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
UIView *contentView = [[UIView alloc] initWithFrame:applicationFrame];
contentView.backgroundColor = [UIColor redColor]; // red color only for debug purposes
self.view = contentView;
}
Leave the viewDidLoad method as I wrote and see what happens.
When you create the view controller use only init method.
MenuViewController *vc = [[MenuViewController alloc] init];
Your UILabel's frame has size.width=0:
CGRectMake(0,100,0,100)
and if B.jpg is not added to the project you UIImageView will also be empty.
Also, if second UIViewController doesn't have a XIB, initialize it using the - (id)init method instead of - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil.
I watched the WWDC video on UIViewController Containment and read through this blog post: http://www.cocoanetics.com/2012/04/containing-viewcontrollers/
but I can't get my initial view controller to show. Is there something I am missing? In my ContainerViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_homeViewController = [[HomeViewController alloc] init];
_detailViewController = [[DetailViewController alloc] init];
[self setSubViewControllers:#[_homeViewController, _detailViewController]];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (_selectedViewController.parentViewController == self) {
// nothing to do
return;
}
// adjust the frame to fit the container view
_selectedViewController.view.frame = _containerView.bounds;
// make sure that it resizes on rotation automatically
_selectedViewController.view.autoresizingMask = _containerView.autoresizingMask;
// add as child VC
[self addChildViewController:_selectedViewController];
// add it to container view, calls willMoveToParentViewController for us
[_containerView addSubview:_selectedViewController.view];
// notify that move is done
[_selectedViewController didMoveToParentViewController:self];
}
- (void)loadView {
// set up the base view
CGRect frame = [[UIScreen mainScreen] bounds];
UIView *aView = [[UIView alloc] initWithFrame:frame];
aView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
aView.backgroundColor = [UIColor blueColor];
// set up content view
_containerView = [[UIView alloc] initWithFrame:frame];
_containerView.backgroundColor = [UIColor grayColor];
_containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[aView addSubview:_containerView];
self.view = aView;
}
- (void)setSubViewControllers:(NSArray *)subViewControllers {
_subViewControllers = [subViewControllers copy];
if (_selectedViewController) {
// remove previous VC
}
_selectedViewController = _subViewControllers[0];
}
My ContainerViewController is the initial view controller in my storyboard. I see that it shows on the simulator, but the HomeViewController (the first child view controller in my container) does not show.
When I step through the debugger, the subViewControllers property of my ContainerViewController does have the homeViewController and detailViewController in it. The viewDidLoad of HomeViewController also does get called. I just don't see anything on screen except the background color of the ContainerViewController.
Any thoughts? Thanks.
So I'm not the brightest person in the world, but the reason nothing was being shown on the screen was because the nibs were in the storyboard and I needed to do this instead:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPad" bundle:nil];
_homeViewController = [storyboard instantiateViewControllerWithIdentifier:#"HomeViewController"];
_detailViewController = [storyboard instantiateViewControllerWithIdentifier:#"DetailViewController"];
Hopefully this helps someone who is also not familiar with Storyboards yet.
You have an NSArray, but you are trying to access it as a C array.
_subViewControllers[0]
should be:
[_subViewControllers objectAtIndex:0];
That being said, you seem to have some code that could be better in other methods. I would personally clean this up a lot and make it much simpler. I would remove loadView and _containerView, and just use self.view as one normally would. For what you are trying to do, there really doesn't even seem a need to track parent and child view controllers. Anyway, this is how I would do it:
#interface ContainerViewController ()
#property (nonatomic, retain) NSArray *subViewControllers;
#end
#implementation ObservationReportViewController {
UIViewController *_selectedViewController;
}
#synthesize subViewControllers = _subViewControllers;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
HomeViewController *homeViewController = [[HomeViewController alloc] init];
homeViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
DetailViewController *detailViewController = [[DetailViewController alloc] init];
detailViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
// Retain the view controllers.
self.subViewControllers = #[homeViewController, detailViewController];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self setSelectedViewController: [_subViewControllers objectAtIndex:0]];
}
-(void)setSelectedViewController:(UIViewController *)selectedViewController {
if (_selectedViewController != selectedViewController) {
[_selectedViewController.view removeFromSuperview];
_selectedViewController = selectedViewController;
// adjust the frame to fit the container view
[self.view addSubview:_selectedViewController.view];
//_selectedViewController.view.frame = _containerView.bounds;
_selectedViewController.view.frame = self.view.bounds;
}
}
If you set the InitialViewController through the storyboard in a different storyb than the MainStoryboard, then you need to update the project settings to use that new storyboard.
Go to project settings, General and set the Main Interface setting to the new storyboard