I'm trying to understand how to minimize my transition time between my view controllers.
For some reason, segment switching to one of my controllers takes 1204.0 ms.
In instruments it is telling me that this method is taking 964.0 ms.
- (void)goToNextContentViewController
{
self.index = [NSNumber numberWithInt:1];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MusicPlayerQueue" bundle:nil];
SABaseContentViewController *queueViewController = [storyboard instantiateViewControllerWithIdentifier:#"Queue"];
queueViewController.rootViewController = self;
[self.pageViewController setViewControllers:#[queueViewController]
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:^(BOOL finished) {
}];
}
Specifically when I select a segmented control.
- (IBAction)segmentSwitch:(UISegmentedControl *)sender
{
UISegmentedControl *segmentedControl = (UISegmentedControl *) sender;
NSInteger selectedSegment = segmentedControl.selectedSegmentIndex;
if (selectedSegment == 0) {
[self goToPreviousContentViewController];
}
else{
[self goToNextContentViewController];
}
}
I am pushing to a tableViewController that is loading data that I am populating from a singleton. Any ideas why this is happening? My other segment tab loads the view controller at a much faster speed with the same method.
The strangest part is that the view loads pretty fast, ONLY when the tableView in the controller I am pushing to is populated with 3 or less objects from my SingletonArray. If the array is 3 or greater, it will load at a speed of 1000+ms....
Here is my viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.tableView setEditing:YES];
self.editSelected = NO;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(itemDidFinishPlaying:) name:#"songEnded" object:nil];
}
Related
I have a UIPageViewController that I've set up with an array as the datasource. I see the first page fine and the presentation count dots show up correctly, but when I try to drag the to the next page nothing happens. So I set up some breakpoints in the viewControllerAfterViewController as well as Before methods and they never get called on. The other dataSource methods for presentationCountForPageViewController get called on fine.
Any idea what I am missing? I've been going line by line with examples I've found on the web but can't find anything.
- (void)viewDidLoad
{
[super viewDidLoad];
UIPageViewController *pageController = self.pageController;
pageController.dataSource = self;
UIChildViewController *initialViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = #[initialViewController];
[pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
[self addChildViewController:pageController];
[self.view addSubview:pageController.view];
[pageController didMoveToParentViewController:self];
}
- (UIPageViewController *)pageController
{
return !_pageController ? _pageController =
({
UIPageViewController *value = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options:nil];
value.view.frame = self.view.bounds;
value;
}) : _pageController;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pa geViewController viewControllerBeforeViewController:(UIChildViewController *)viewController
{
NSUInteger index = viewController.index;
return (index == 0 ) ? nil : [self viewControllerAtIndex:--index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIChildViewController *)viewController
{
NSUInteger index = viewController.index;
index++;
return (index == self.myDataSourceArray.count) ? nil : [self viewControllerAtIndex:index];
}
- (UIChildViewController *)viewControllerAtIndex:(NSUInteger)index
{
UIChildViewController *childViewController = [UIChildViewController new];
childViewController.view.frame = self.pageController.view.bounds;
childViewController.index = index;
...
return childViewController;
}
- (NSInteger)presentationCountForPageViewController: (UIPageViewController *)pageViewController
{
// The number of items reflected in the page indicator.
return self.myDataSourceArray.count;
}
- (NSInteger)presentationIndexForPageViewController:(UI PageViewController *)pageViewController
{
// The selected item reflected in the page indicator.
return 0;
}
The problem was that in including my UIViewController subclass which encapsulated the UIPageViewController, I forgot in the parent view controller's viewDidLoad to include addChildViewController and didMoveToParentViewController
[self addChildViewController:myViewController];
[self.view addSubview:myViewController.view];
[myViewControllerController didMoveToParentViewController:self];
Fixed the problem.
I have a UITableView inside of an UITabBarController. Now, I am already checking to see if a user is logged in, and if they are not logged in I display a Modal View Controller to have them log in or sign up. But here's my problem, when the user hit's cancel, the user goes back to the original position of the table view. I can't have users see the rows in table view if they are not signed in. If a user is not logged in, I want a message exactly how the examples Apple gives in the iTunes store and the "Popular near me" examples in the Apple Human Interface Guideline:
https://developer.apple.com/library/iOS/documentation/userexperience/conceptual/mobilehig/StartingStopping.html#//apple_ref/doc/uid/TP40006556-CH52-SW1
So how would I display a message like that in a tableview controller? Keep in mind, I will always have data for that table view controller. Hopefully I am clear for everyone. Would I just bring the tableview background to the front of the tableview rows?
// ATableViewController embedded in a NavigationController with UITabBar
- (void)viewWillAppear:(BOOL)animated
{
// NSLog(#"dateViewDidLoad %f", [[NSDate date] timeIntervalSince1970]);
[super viewWillAppear:animated];
NSUserDefaults *textDef = [NSUserDefaults standardUserDefaults];
NSString *userName = [textDef stringForKey:#"userName"];
if (userName == nil) {
SignUpViewController *signup = [[SignUpViewController alloc]initWithNibName:#"SignUpViewController" bundle:nil];
[signup setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentViewController:signup animated:YES completion:nil];
// Display message you need to sign in to view this content
} else {
// Proceed and display the rows
}
}
If you use a UITableViewController you could "abuse" tableHeaderView of the tableView, by resizing it to full screen and disabling the dataSource methods and scrolling.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (isLoggedIn) {
self.tableView.tableHeaderView = nil;
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.scrollEnabled = YES;
[self.tableView reloadData];
}
else {
if (!self.tableView.tableHeaderView) {
UIView *viewToDisplayIfNotLoggedIn = [[UIView alloc] initWithFrame:self.view.bounds];
viewToDisplayIfNotLoggedIn.backgroundColor = [UIColor redColor];
self.tableView.tableHeaderView = viewToDisplayIfNotLoggedIn;
}
self.tableView.delegate = nil;
self.tableView.dataSource = nil;
self.tableView.scrollEnabled = NO;
[self.tableView reloadData];
}
}
If you are using a normal UIViewController it's even easier than that, just hide the tableView and show another UIView:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (isLoggedIn) {
self.tableView.hidden = NO;
self.viewToDisplayIfNotLoggedIn.hidden = YES;
}
else {
self.tableView.hidden = YES;
if (!self.viewToDisplayIfNotLoggedIn) {
self.viewToDisplayIfNotLoggedIn = [[UIView alloc] initWithFrame:self.view.bounds];
self.viewToDisplayIfNotLoggedIn.backgroundColor = [UIColor redColor];
[self.view addSubview:self.viewToDisplayIfNotLoggedIn];
}
self.viewToDisplayIfNotLoggedIn.hidden = NO;
}
}
I m using UIPageViewController on iPad where I need to show a firstviewController in the first page and ContentViewController in the next page in landscape.
If I set the NSArray with two viewControllers the app is crashes at [self.pagviewController setViewController:] with the following exception:
The number of provided view controllers (2) doesn't match the number required (1) for the requested spine location (UIPageViewControllerSpineLocationMin)
Below is the code:
#pragma mark - UIPageViewControllerDataSource Methods
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger currentIndex = [self.modelArray indexOfObject:[(ContentViewController *)viewController textContents]];
if(currentIndex == 0)
{
return nil;
}
ContentViewController *contentViewController = [[ContentViewController alloc] init];
contentViewController.textContents = [self.modelArray objectAtIndex:currentIndex - 1];
return contentViewController;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger currentIndex = [self.modelArray indexOfObject:[(ContentViewController *)viewController textContents]];
if(currentIndex == self.modelArray.count-1)
{
return nil;
}
ContentViewController *contentViewController = [[ContentViewController alloc] init];
contentViewController.textContents = [self.modelArray objectAtIndex:currentIndex + 1];
return contentViewController;
}
//#pragma mark - UIPageViewControllerDelegate Methods
- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController
spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation
{
if(UIInterfaceOrientationIsPortrait(orientation))
{
//Set the array with only 1 view controller
UIViewController *currentViewController = [self.pageViewController.viewControllers objectAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:currentViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
//Important- Set the doubleSided property to NO.
self.pageViewController.doubleSided = NO;
//Return the spine location
return UIPageViewControllerSpineLocationMin;
}
else
{
NSArray *viewControllers = nil;
ContentViewController *currentViewController = [self.pageViewController.viewControllers objectAtIndex:0];
NSUInteger currentIndex = [self.modelArray indexOfObject:[(ContentViewController *)currentViewController textContents]];
if(currentIndex == 0 || currentIndex %2 == 0)
{
UIViewController *nextViewController = [self pageViewController:self.pageViewController viewControllerAfterViewController:currentViewController];
viewControllers = [NSArray arrayWithObjects:currentViewController, nextViewController, nil];
}
else
{
UIViewController *previousViewController = [self pageViewController:self.pageViewController viewControllerBeforeViewController:currentViewController];
viewControllers = [NSArray arrayWithObjects:previousViewController, currentViewController, nil];
}
//Now, set the viewControllers property of UIPageViewController
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
return UIPageViewControllerSpineLocationMid;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
//Instantiate the model array
self.modelArray = [[NSMutableArray alloc] init];
self.vcs = [[NSMutableArray alloc]init];
for (int index = 1; index <= 2 ; index++)
{
[self.modelArray addObject:[NSString stringWithFormat:#"Page %d",index]];
}
//Step 1
//Instantiate the UIPageViewController.
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
//Step 2:
//Assign the delegate and datasource as self.
self.pageViewController.delegate = self;
self.pageViewController.dataSource = self;
//Step 3:
//Set the initial view controllers.
appDelegate.contentViewController.textContents = [self.modelArray objectAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObjects:appDelegate.firstViewController,appDelegate.contentViewController,nil];
[self.pageViewController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
//Step 4:
//ViewController containment steps
//Add the pageViewController as the childViewController
[self addChildViewController:self.pageViewController];
//Add the view of the pageViewController to the current view
[self.view addSubview:self.pageViewController.view];
//Call didMoveToParentViewController: of the childViewController, the UIPageViewController instance in our case.
[self.pageViewController didMoveToParentViewController:self];
//Step 5:
// set the pageViewController's frame as an inset rect.
CGRect pageViewRect = self.view.bounds;
pageViewRect = CGRectInset(pageViewRect, 40.0, 40.0);
self.pageViewController.view.frame = pageViewRect;
//Step 6:
//Assign the gestureRecognizers property of our pageViewController to our view's gestureRecognizers property.
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
}
The problem is you passing an array containing two view controllers to the page view controller while it expects one at a time, change your array to be like this :
NSArray *viewControllers = #[appDelegate.firstViewController];
You will pass one of the views but viewControllerAfterViewController and viewControllerBeforeViewController will handle the rest.
Ah..Finally got solution for this same issue.., it may helps you..
When we set the spine location to UIPageViewControllerSpineLocationMid, the doubleSided property of the pageViewController is automatically set to YES. This means that the content on page front will not partially show through back. But when this property is set to NO, the content on page front will partially show through back, giving the page a translucent kind of effect. So, in the portrait orientation, we have to set the value to NO, otherwise it would result in an exception.
So in your UIPageviewcontroller delegate method, in else part add this doubleSided property as YES when you return spineLocation as UIPageViewControllerSpineLocationMid
self.pageViewController.doubleSided = YES;
return UIPageViewControllerSpineLocationMid;
self.pageViewController.doubleSided = NO;
return UIPageViewControllerSpineLocationMid;
This is the solution for the exception.
In xcode it self you could find this.
Go to the UIPageViewcontroller class there you could see the explanation for this like:
#property (nonatomic, readonly) UIPageViewControllerSpineLocation spineLocation; // If transition style is 'UIPageViewControllerTransitionStylePageCurl', default is 'UIPageViewControllerSpineLocationMin', otherwise 'UIPageViewControllerSpineLocationNone'.
// Whether client content appears on both sides of each page. If 'NO', content on page front will partially show through back.
// If 'UIPageViewControllerSpineLocationMid' is set, 'doubleSided' is set to 'YES'. Setting 'NO' when spine location is mid results in an exception.
#property (nonatomic, getter=isDoubleSided) BOOL doubleSided; // Default is 'NO'.
Instead of implementing a full data source, you can set the PageViewController with one view controller at a time each time the user pushes a next or back button, like
[pageViewController setViewControllers:#[contentViewController]
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:nil];
This will animate the page transition as you switch.
I'm trying to have something similar to a UINavigationController so I can customize the animations. To start, I'm just using Apple stock animations. Here's my containerViewController:
- (void)loadView {
// Set up content view
CGRect frame = [[UIScreen mainScreen] bounds];
_containerView = [[UIView alloc] initWithFrame:frame];
_containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.view = _containerView;
}
- (id)initWithInitialViewController:(UIViewController *)vc {
self = [super init];
if (self) {
_currentViewController = vc;
[self addChildViewController:_currentViewController];
[self.view addSubview:_currentViewController.view];
[self didMoveToParentViewController:self];
_subViewControllers = [[NSMutableArray alloc] initWithObjects:_currentViewController, nil];
}
return self;
}
- (void)pushChildViewController:(UIViewController *)vc animation:(UIViewAnimationOptions)animation {
vc.view.frame = _containerView.frame;
[self addChildViewController:vc];
[self transitionFromViewController:_currentViewController toViewController:vc duration:0.3 options:animation animations:^{
}completion:^(BOOL finished) {
[self.view addSubview:vc.view];
[vc didMoveToParentViewController:self];
[self.subViewControllers addObject:vc];
}];
}
- (void)popChildViewController:(UIViewController *)vc WithAnimation:(UIViewAnimationOptions)animation {
// Check that there is a view controller to pop to
if ([self.subViewControllers count] <= 0) {
return;
}
NSInteger idx = [self.subViewControllers count] - 1;
UIViewController *toViewController = [_subViewControllers objectAtIndex:idx];
[vc willMoveToParentViewController:nil];
[self transitionFromViewController:vc toViewController:toViewController duration:0.3 options:animation animations:^{
}completion:^(BOOL finished) {
[vc.view removeFromSuperview];
[vc removeFromParentViewController];
[self didMoveToParentViewController:toViewController];
[self.subViewControllers removeObjectAtIndex:idx];
}];
}
I have this ContainerViewcontroller as my rootViewController of the window. I can add my initial viewController and push a view controller. When I try to pop though, I get
ContainerViewController[65240:c07] Unbalanced calls to begin/end appearance transitions for <SecondViewController: 0x8072130>.
I'm wondering what I am doing wrong. I figured my initialViewController is still underneath the secondViewController. Any thoughts? Thanks!
I don't know if this is what's causing your problem, but shouldn't this:
[self didMoveToParentViewController:toViewController];
be:
[toViewController didMoveToParentViewController:self];
Also, I'm not sure what you're doing with the subViewControllers array. It seems to be a duplication of the childViewControllers array that is already a property of a UIViewController.
One other thing I'm not sure is right. In your pop method your toViewController is the last controller in the _subViewControllers array. Don't you want it to be the second to last? Shouldn't the last be the one you're popping? You're popping vc, which is a controller you're passing in to the method, I don't understand that.
This is the way I've made a navigation like controller. In its containment behavior, it acts like a navigation controller, but without a navigation bar, and allows for different transition animations:
#implementation ViewController
-(id)initWithRootViewController:(UIViewController *) rootVC {
if (self = [super init]) {
[self addChildViewController:rootVC];
rootVC.view.frame = self.view.bounds;
[self.view addSubview:rootVC.view];
}
return self;
}
-(void)pushViewController:(UIViewController *) vc animation:(UIViewAnimationOptions)animation {
vc.view.frame = self.view.bounds;
[self addChildViewController:vc];
[self transitionFromViewController:self.childViewControllers[self.childViewControllers.count -2] toViewController:vc duration:1 options:animation animations:nil
completion:^(BOOL finished) {
[vc didMoveToParentViewController:self];
NSLog(#"%#",self.childViewControllers);
}];
}
-(void)popViewControllerAnimation:(UIViewAnimationOptions)animation {
[self transitionFromViewController:self.childViewControllers.lastObject toViewController:self.childViewControllers[self.childViewControllers.count -2] duration:1 options:animation animations:nil
completion:^(BOOL finished) {
[self.childViewControllers.lastObject removeFromParentViewController];
NSLog(#"%#",self.childViewControllers);
}];
}
-(void)popToRootControllerAnimation:(UIViewAnimationOptions)animation {
[self transitionFromViewController:self.childViewControllers.lastObject toViewController:self.childViewControllers[0] duration:1 options:animation animations:nil
completion:^(BOOL finished) {
for (int i = self.childViewControllers.count -1; i>0; i--) {
[self.childViewControllers[i] removeFromParentViewController];
}
NSLog(#"%#",self.childViewControllers);
}];
}
After Edit: I was able to duplicate the back button function with this controller by adding a navigation bar to all my controllers in IB (including in the one that is the custom container controller). I added a bar button to any controllers that will be pushed, and set their titles to nil (I got some glitches if I left the title as "item"). Deleting that title makes the button disappear (in IB) but you can still make connections to it in the scene list. I added an IBOutlet to it, and added this code to get the function I wanted:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (self.isMovingToParentViewController) {
self.backButton.title = [self.parentViewController.childViewControllers[self.parentViewController.childViewControllers.count -2] navigationItem].title;
}else{
self.backButton.title = [self.parentViewController.childViewControllers[self.parentViewController.childViewControllers.count -3] title];
}
}
I've shown two different ways that worked to access a title -- in IB you can set a title for the controller which I used in the else clause, or you can use the navigationItem title as I did in the if part of the clause. The "-3" in the else clause is necessary because at the time viewWillAppear is called, the controller that is being popped is still in the childViewControllers array.
addChildViewController should be called first
For adding / removing, you can refer to this great category and have no worry when to call it:
UIViewController + Container
- (void)containerAddChildViewController:(UIViewController *)childViewController {
[self addChildViewController:childViewController];
[self.view addSubview:childViewController.view];
[childViewController didMoveToParentViewController:self];
}
- (void)containerRemoveChildViewController:(UIViewController *)childViewController {
[childViewController willMoveToParentViewController:nil];
[childViewController.view removeFromSuperview];
[childViewController removeFromParentViewController];
}
In addition to rdelmar's answer you should not be calling addView/removeFromSuperview transitionFromViewController does this for you, from the documentation:
This method adds the second view controller’s view to the view
hierarchy and then performs the animations defined in your animations
block. After the animation completes, it removes the first view
controller’s view from the view hierarchy.
I've made a test app to familiarize myself with making a custom container view controller. If I rotate the device when the app first starts or after switching to a different view controller, the new view resizes to take up the whole screen, as I intended. However, if I rotate after the app starts, and then switch to a new view controller, the view keeps its portrait size instead of getting shorter and wider (actually it's slightly different -- it goes from 320,460 to 300,480). The master view controller is alloc init'd in the app delegate (no xib) and set as the window's root view controller. Here is the code I have in my MasterViewController (the custom container controller):
- (void)viewDidLoad {
[super viewDidLoad];
WelcomeController *welcome = [[WelcomeController alloc] initWithNibName:#"ViewController" bundle:nil];
self.currentController = welcome;
[self addChildViewController:welcome];
[self.view addSubview:welcome.view];
UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeLeft:)];
swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
[self.view addGestureRecognizer:swipeLeft];
}
- (void)swipeLeft:(UISwipeGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateRecognized) {
UIActionSheet *sheet =[[UIActionSheet alloc] initWithTitle:#"Select A Destination" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"welcome",#"Play",#"Scores", nil];
[sheet showInView:self.view];
}
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
switch (buttonIndex) {
case 0:{
if ([self.currentController class] != [WelcomeController class] ) {
WelcomeController *welcome = [[WelcomeController alloc] initWithNibName:#"ViewController" bundle:nil];
[self addChildViewController:welcome];
[self moveToNewController:welcome];
}
break;
}
case 1:{
if ([self.currentController class] != [PlayViewController class] ) {
PlayViewController *player = [[PlayViewController alloc] initWithNibName:#"PlayViewController" bundle:nil];
[self addChildViewController:player];
[self moveToNewController:player];
}
break;
}
case 2:{
if ([self.currentController class] != [HighScores class] ) {
HighScores *scorer = [[HighScores alloc] initWithNibName:#"HighScores" bundle:nil];
[self addChildViewController:scorer];
[self moveToNewController:scorer];
}
break;
}
case 3:
NSLog(#"Cancelled");
break;
default:
break;
}
}
-(void)moveToNewController:(id) newController {
[self.currentController willMoveToParentViewController:nil];
[self transitionFromViewController:self.currentController toViewController:newController duration:.6 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{}
completion:^(BOOL finished) {
[self.currentController removeFromParentViewController];
[newController didMoveToParentViewController:self];
self.currentController = newController;
}];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;//(interfaceOrientation == (UIInterfaceOrientationPortrait | UIInterfaceOrientationLandscapeLeft));
}
Any ideas why this is happening (I don't know if this means that the master view controller's view isn't resizing, but when I get this non-resizing behavior the gesture recognizer only responds in the narrow view, not over the whole screen)?
You are not sending rotation messages to your child view controllers. At least not in the code you posted. After switching Child Controller you are even removing previous child from ChildViewControllers array with [self.currentController removeFromParentViewController] so even if you implement - (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers you have always only one ChildViewController in your ParentViewController.
I have got this working, so i will paste you how am i doing this. First i create all my ViewControllers, add them as child view controllers to ParentViewController. Then call didMoveToParentViewController: method.
//Controller1
Controller1 *c1 = [[Controller1 alloc] init];
c1.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self addChildViewController:c1];
[c1 didMoveToParentViewController:self];
//Controller2
Controller2 *c2 = [storyboard instantiateViewControllerWithIdentifier:#"c2"];
index.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self addChildViewController:c2];
[c2 didMoveToParentViewController:self];
c2.view.frame = m_contentView.frame;
[self.view addSubview:c2.view]; //It is in initial screen so set it right away
m_selectedViewController = c2;
//Controller3
Controller3 *c3 = [storyboard instantiateViewControllerWithIdentifier:#"c3"];
compare.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self addChildViewController:c3];
[c3 didMoveToParentViewController:self];
m_controllers = [NSArray arrayWithObjects:c1, c2, c3, nil]; //Hmm now i think this is not needed, I can access viewController directly from self.childViewControllers array
Then I implemented
- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers
{
return YES;
}
Switching to child view controller is done with this code
if (value < m_controllers.count)
{
UIViewController *contentViewController = [m_controllers objectAtIndex:value];
contentViewController.view.frame = m_contentView.frame;
[self transitionFromViewController:m_selectedViewController toViewController:contentViewController duration:0 options:UIViewAnimationOptionTransitionNone animations:nil completion:^(BOOL finished) {
m_selectedViewController = contentViewController;
}
];
}
This should be enough. But i have got some issues with this so i send rotation messages to unactive Childs myself.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
for (UIViewController *vc in m_controllers)
{
if(vc != m_selectedViewController)
[vc willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
for (UIViewController *vc in m_controllers)
{
if(vc != m_selectedViewController)
[vc willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
for (UIViewController *vc in m_controllers)
{
if(vc != m_selectedViewController)
[vc didRotateFromInterfaceOrientation:fromInterfaceOrientation];
}
}
manually added
self.view.autoresizesSubviews = YES;
inside
- (void)viewDidLoad
and it solved the problem,
for some reason the value inside storyboard was not being used i guess