Why ContentVC's viewWill/DidAppear is called before its parent(PageVC)? - ios

In my case, I use ViewController as parent of PageViewController. And it also be the dataSource of PageViewController by providing ContentViewController.
It's strange that ContentViewController's -viewWill/DidAppear: is called before it's parent, here is what I got from console:
[ContentViewController viewWillAppear:]
[ContentViewController viewDidAppear:]
[ViewController viewWillAppear:]
[PageViewController viewWillAppear:]
[ViewController viewDidAppear:]
[PageViewController viewDidAppear:]
Here are some code from ViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
PageViewController *pageVC = [[PageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];;
pageVC.dataSource = self;
[pageVC setViewControllers:#[[self contentViewControllerWithIndex:0]]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO completion:nil];
pageVC.view.backgroundColor = [UIColor whiteColor];
pageVC.view.frame = self.view.bounds;
[self addChildViewController:pageVC];
[self.view addSubview:pageVC.view];
[pageVC didMoveToParentViewController:self];
}
-(ContentViewController *)contentViewControllerWithIndex:(NSInteger )index {
ContentViewController *vc = [[ContentViewController alloc] init];
vc.index = index;
return vc;
}
Thanks.

If you go through line by line of your code
This line just alloc your PageViewController. It has actually not added it on top of your ViewController. So ViewWillAppear for PageViewController will not get called here.
Code:
PageViewController *pageVC = [[PageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
Below line is calling [self contentViewControllerWithIndex:0] which will be allocating the ContentViewController also adding it on PageVC so ViewWillAppear for ContentViewController is called
Code:
[pageVC setViewControllers:#[[self contentViewControllerWithIndex:0]]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO completion:nil];
Below line is adding PageVC as childViewControllerof ViewController. So once the ViewWillAppear of ViewController will be called then only it can call ViewWillAppear of PageVC and add it as its childView.
Code:
[self addChildViewController:pageVC];
[self.view addSubview:pageVC.view];
[pageVC didMoveToParentViewController:self];

Related

Transferring to another ViewController

I am currently loading another viewcontroller on this code
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
NewViewController *controller = [[NewController alloc]init];
controller.licensed =#"NO";
controller.delegate = self;
self.window.rootViewController = controller;
self.window.backgroundColor = [UIColor clearColor];
[self.window makeKeyAndVisible];
But the problem is when the NewViewController loads. The subviews of the previous view controller is in the background of the NewViewController
[self.rectHolder performSelectorOnMainThread:#selector(removeFromSuperview) withObject:nil waitUntilDone:NO];
[self.btnSignup performSelectorOnMainThread:#selector(removeFromSuperview) withObject:nil waitUntilDone:NO];
[self.view removeFromSuperview];
I tried to use this, but the subviews is still in the background of the new view controller
Edit:
I also tried to use this
NewViewController* viewController = [[NewViewController alloc] init];
viewController.licensed = #"NO";
[self presentViewController:viewController animated:YES completion:nil];
But the subViews of my previous viewcontroller is still in the background

Add Custom View on UIPageViewController

I want to add a Custom View (red View) on the bottom of my UIPageViewController like this:
Because i want some Standard Text which is displayed on every View of my UIPageViewController. Everythings works fine, but my Custom VIew is not visible, this is what i tried:
- (void)viewDidLoad
{
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageController.dataSource = self;
[[self.pageController view] setFrame:[[self view] bounds]];
FirstTutorialViewController *initialViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:self.pageController];
[[self view] addSubview:[self.pageController view]];
[self.pageController didMoveToParentViewController:self];
//Here i try to set the Custom view:
[[self.pageController view] addSubview:[self customView]];
Don't add self customView to the page controller, and be sure to set its frame first.
Instead, resize the page controller to allow space at the bottom for the custom view and add both to your main view.

Reloading Views in UIPageViewController

I am making an iOS application that has a UIPageViewController that is loaded with a default page if there aren't any others added yet, and a user can add pages as he progresses through the app. However, the initial view never changes as others are added.
I've tried the answers from these questions:
Is it possible to Turn page programmatically in UIPageViewController?
Changing UIPageViewController's page programmatically doesn't update the UIPageControl
Removing a view controller from UIPageViewController
Refresh a UIPageViewController
None of them work for me. The view still remains at the initial page until I reload the application, after which, the pages show fine, and I can add as many as I want.
This is the code I have for making the PageView and the pages
- (void)viewDidLoad
{
[super viewDidLoad];
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageController.dataSource = self;
[[self.pageController view] setFrame:[[self pageControllerView] bounds]];
UIViewController *initialViewController = [self viewControllerAtIndex:0];
__block Page1ViewController *blocksafeSelf = self;
// This doesn't work either... :(
void (^completionBlock)(BOOL) = ^(BOOL finished)
{
// It seems that whenever the setViewControllers:
// method is called with "animated" set to YES, UIPageViewController precaches
// the view controllers retrieved from it's data source meaning that
// the dismissed controller might not be removed. In such a case we
// have to force it to clear the cache by initiating a non-animated
// transition.
usleep(1);
dispatch_async(dispatch_get_main_queue(), ^(){
[blocksafeSelf.pageController setViewControllers:#[initialViewController]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
});
};
[self.pageController setViewControllers:#[initialViewController]
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:completionBlock];
[self addChildViewController:self.pageController];
[[self view] addSubview:[self.pageController view]];
[self.pageController didMoveToParentViewController:self];
}
- (void)reloadViews
{
[[self childViewControllers] makeObjectsPerformSelector:#selector(removeFromParentViewController)];
[[self.view subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
[self.pageController willMoveToParentViewController:nil];
[self.pageController removeFromParentViewController];
[self.pageController.view removeFromSuperview];
self.pageController = nil;
self.pageController = [[UIPageViewController alloc] init];
[self.view setNeedsDisplay];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = ((SomethingViewController *)viewController).index;
index++;
if (index >= [Settings somethings].count)
{
return nil;
}
return [self viewControllerAtIndex:index];
}
- (UIViewController *)viewControllerAtIndex:(NSUInteger)index
{
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Storyboard_iPhone"
bundle:nil];
if ([Settings somethings].count == 0 && index == 0)
{
NoSomethingViewController *vc = [sb instantiateViewControllerWithIdentifier:#"NoSomethingViewController"];
vc.index = index;
return vc;
}
SomethingViewController *childViewController = [sb instantiateViewControllerWithIdentifier:#"SomethingViewController"];
childViewController.something = [[Settings somethings] somethingAtIndex:index];
childViewController.index = index;
return childViewController;
}
When a new page should be created, by adding a something in the somethings array, I call reloadViews from the View controller that did the adding of the something. The code then hits the second part of viewControllerAtIndex, but that is not shown on the page that I see on the phone, as I still see the NoSomethingViewController and it's view.
If you need more code, I'll provide.
add the following code in the pageViewController viewWillAppear method
dataSource = self
and in the viewWillDisappear add
dataSource = nil
this will force the pageViewController to reload its dataSource
To show the current dot, dont forget you have to update the page indicator
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
Example how to update your UIPageControl indicator https://stackoverflow.com/a/22576250/3897011
After a long time and after wasting a support ticket with Apple, I decided to go with another approach.
In my Storyboard I created 2 different navigation controllers, one for each case (if there are somethings and if there aren't any), and I have an initial view Controller that, on viewDidAppear, instantiates one of the two and presents it. This way, I make sure that the entire navigation controller gets reloaded correctly.
UINavigationController *nc;
if ([Settings somethings].count)
{
nc = [self.storyboard instantiateViewControllerWithIdentifier:#"NavigationController"];
}
else
{
nc = [self.storyboard instantiateViewControllerWithIdentifier:#"NoSomethingNavigationController"];
}
self.nc = nc;
[self presentViewController:nc animated:NO completion:nil];
In order to reload UIPageViewController you can use the following code:
[self.pageController setViewControllers:#[yourCurrentController]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
Also please implement
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
method.

Delegate between UIViewControllers

I have following structure of ViewControllers:
PageViewController contains PhotoViewController and VideoViewController, that changing programmatically, so there no any segues.
I want allow VideoControlViewController to use methods from CameraViewController. I tried to use following code:
self.videoControlViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"videoControlViewController"];
self.videoControlViewController.delegate = self;
It don't works because method "instantiateViewControllerWithIdentifier" creates new instance of VideoViewController. Here is topic with the same problem that I found:
http://iphonedevsdk.com/forum/iphone-sdk-development/109543-string-becomes-nil-after-viewdidload-with-protocol-and-delegate.html
How can I point self.VideoControlViewController to its instance from storyboard if there no any segues or transitions?
- (void)viewDidLoad {
[super viewDidLoad];
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.viewControllers = #[#"photoControlViewController", #"videoControlViewController"];
self.pageViewController.dataSource = self;
[[self.pageViewController view] setFrame:[[self view] bounds]];
[self.pageViewController setViewControllers:[NSArray arrayWithObject:[self viewControllerAtIndex:[self.viewControllers indexOfObject:#"photoControlViewController"]]] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:self.pageViewController];
[[self view] addSubview:[self.pageViewController view]];
[self.pageViewController didMoveToParentViewController:self];
}

Issue with iOS7 and UIPageViewController

I have a UIPageViewController that is added as subview on UIView. The UIView sits on the top of UIViewController's view, at start it puts the UIPageViewController lower than it should sit, but right after I click on the next button to push the next UIPageViewController's view, it send it back to the correct position.
What is he doing that? I tried everything but still can figure out the problem.
This is how it looks:
What seems to be the problem? Thanks in advance!
EDIT: This is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
DataChildViewController *initialViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
self.pageController.dataSource = self;
self.pageController.delegate = self;
self.pageController.view.userInteractionEnabled = NO;
self.pageController.view.frame = self.view.bounds;
[self.pageControllerParent addSubview:self.pageController.view];
[self addChildViewController:self.pageController];
self.currentPageControllerIndex = 1;
}
- (IBAction)buttonNextDidClicked
{
self.buttonNext.enabled = NO;
__weak typeof(self) __self = self;
[self.pageController setViewControllers:#[[self viewControllerAtIndex:self.currentPageControllerIndex]]
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:^(BOOL finished) {
__self.currentPageControllerIndex++;
__self.buttonNext.enabled = YES;
}];
}
#pragma mark - UIPageViewControllerDelegate & DataSource
- (DataChildViewController *)viewControllerAtIndex:(NSUInteger)index
{
DataChildViewController *childViewController = [[DataChildViewController alloc] initWithNibName:#"DataChildViewController" bundle:nil];
childViewController.index = index;
return childViewController;
}
So, I've figured out the problem.
On viewDidLoad I had this line:
self.pageController.view.frame = self.view.bounds;
When it actually should be:
self.pageController.view.frame = self.pageControllerParent.bounds;

Resources