I'm trying to add a UIKit ViewController on top of a cocos2d scene. Everything works great, but I need to run [[CCDirector sharedDirector] stopAnimation] AFTER the UIKit view is loaded completely.
I push a button and have a 1 second transition to the new scene being loaded. I have tried adding stopAnimation to every callback in both the UIViewController(ViewDidLoad, ViewDidLayoutSubviews, etc) and the Cocos2d scene. What happens is the scene is loaded but the animation is stopped before the UIViewController is completely loaded, which prevents the view from loading at all.
I could set a timer for the transition duration and then call stopAnimation but I would rather not do it that way. Is there any sort of delegate method I'm missing here?
You need to call that method from your view controller's viewDidLoad method:
- (void) viewDidLoad
{
[super viewDidLoad];
[[CCDirector sharedDirector]stopAnimation];
}
Related
I have a UIViewController class that contains a WKWebView and implements WKNavigationDelegate.
I would like to detect when a the view controller appears again. I understand the method loadView but, if I push a new view on the stack and then go back from that view to the previous view (my view controller) which method is called on the view controller?
The method that will be called is viewWillAppear:.
If you push to next view then viewDidLoad will be called first
Then viewWillAppear, viewDidAppear
If you pop to previous screen again (your UIViewController) then
viewWillAppear will be called first and after entire view appears
then viewDidAppear will be called..
viewDidAppear is useful in the cases where any method called at viewWillAppear after that you can Load the data at ViewDidAppear..
The ViewControllers viewDidLoad method is only called once when the view is created for the first time.
// viewDidLoad is called only once when the view is created for the first time
- (void) viewDidLoad
{
[super viewDidLoad];
// do your code here
}
You can also implement the below two methods in side your ViewController.m class
// viewWillAppear is called just before the view is about to be appeared
- (void) viewWillAppear
{
[super viewWillAppear];
// do your code here
}
// is called when the view has appeared
- (void) viewDidAppear
{
[super viewDidAppear];
// do your code here
}
I've got a game with a MasterViewController. It has a "Play" button that segues to the GameViewController. The GameViewController and GameScene are plain vanilla what a game build provides except I added an NSLog to the GameScene's update method and, on the storyboard, created a "Quit" button that segues back from the GameViewController to the MasterViewController.
Everything works as expected. I fire up the app and touch the Play button and it transitions to the GameViewController to the GameScene. Fine, I see the standard "Hello World" message and can touch to create spinning spaceships. I start getting the NSLog output from the update method. Great.
However, when I click the Quit button and it segues back to the MasterViewController, I am still getting the NSLog output from the GameScene update method so the GameScene is still active. I want the GameScene gone. Added a dealloc to the GameScene and it is never called, probably because of ARC.
In the GameViewController I added a weak gameScene property and:
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
NSLog(#"viewWillDisappear");
[_gameScene removeAllChildren];
[_gameScene removeAllActions];
[_gameScene removeFromParent];
_gameScene = nil;
}
Still getting the NSLog output from the GameScene update method. Sigh... How do I kill the GameScene dead, dead, dead?
I did the Play/Quit/Play/Quit transition several times. The output from the update method is:
2014-11-20 12:48:41.551 Demo[7386:2004098] update: 0x7b091090
2014-11-20 12:48:42.095 Demo[7386:2004098] update: 0x7ed21020
2014-11-20 12:48:42.656 Demo[7386:2004098] update: 0x7eb1c4b0
2014-11-20 12:48:43.217 Demo[7386:2004098] update: 0x7b091090
2014-11-20 12:48:43.762 Demo[7386:2004098] update: 0x7ed21020
2014-11-20 12:48:44.322 Demo[7386:2004098] update: 0x7eb1c4b0
So all of my GameScenes are still active in the background.
You must make sure no other objects are pointing strongly to the object you want to remove from memory. See Apple Developer.
I found a workaround - use a nav controller, which I alway hide to make room for my game. To transition to the next view controller in the hierarchy, use a "Show" segue. To pop back, add your own Back button and connect the action:
- (IBAction)backButtonClicked:(UIButton *)sender {
[[self navigationController] popViewControllerAnimated:YES];
}
I also have one place in my GameViewController where I use a "Pause" button to pop all the way back to the root view controller.
- (IBAction)pauseButtonClicked:(UIButton *)sender {
NSArray * viewControllers = self.navigationController.viewControllers;
NSLog(#"nav view controllers: %#", viewControllers);
UIViewController * targetViewController = viewControllers[0];
NSLog(#"target controller: %#", targetViewController);
[self.navigationController popToViewController:targetViewController animated:YES];
}
All this correctly deallocates the GameViewController and GameScene when they disappear.
I've a GLKViewController which renders an OpenGL 2.0 scene. All works fine, but when I segue to a new storyboard scene (via a UINav Controller) and then return to the OpenGL ES 2.0 scene, the update and drawRect methods in the view controller are no longer called.
I've tried setting self.paused to NO in the viewDidLoad method, but to no avail.
Can anyone suggest what is happening here ?
The GLKViewController contains a UIView, both of which are set in the storyboard. This is the segue to the view from the GLKViewController :
if ([segue.identifier isEqualToString:#"GoToEntry"]) {
DetailViewController *d = segue.destinationViewController;
d.selection = currentSelection;
}
Ok - the problem was that GLKViewController sets paused to YES when view exits. viewWillAppear wasn't actually being called - moving self.paused to viewDidAppear solved the problem.
Newest Update: I created a brand new project that is built the exact same way as below. However, this test project actually works just fine even though it seems to be the same... One thing I've noticed is that the parent view controller in the broken version is receiving the -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event when clicking on the child view controller's view... In the working version, the child view controller receives the event as it should... It's as if the parent view is blocking the child view or something..?
Progress Update: Upon screwing around a bit I have found that it works fine when directly assigning a frame to the child view controllers. However, I have to create my project using autolayout so that is what I've done. For some reason, autolayout is causing the child view controller's view to be unresponsive...
At the moment I have a viewcontroller which has just 1 childviewcontroller.
The childviewcontroller's view shows up just fine but I cannot interact with the childViewController at all.
The childViewController has a couple of UIButtons but they do not respond to clicks.
I tried testing with this in both the parent and child viewcontrollers.
(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touched!");
}
When clicking in the frame of the child view controller's view, this method responds in the parent view controller but not the child view controller.
The child view controller also works correctly when directly creating it and setting it as the root view controller in the app delegate.
The code I'm using in the parent view controller:
(void) viewDidLoad
{
[super viewDidLoad];
self.detailPageVC = [[GoalDetailsPageViewController alloc] init];
[self.view addSubview:self.detailPageVC.view];
[self addChildViewController:self.detailPageVC];
[self.detailPageVC didMoveToParentViewController:self];
}
Thanks for helping out a rookie! :)
the actual problem was in my GoalDetailsPageViewController. The issue was actually caused by trying to use autolayout within a uiscrollview... a tricky thing. Anyways, the original code I posted is fine, thanks.
Well, I can only suggest the following:
Make sure the userInteractionEnabled property of your buttons and the child ViewController's view is set to YES.
Double check that your view is not 'hidden' nor has an alpha of 0.0.
Confirm the exclusiveTouch of your partent ViewController's view is not set to YES.
Hope this helps!
My solution:
- (void) displayContentController: (UIViewController*) content{
[content.view setFrame:recorderView.bounds];
UINavigationController *childNavController = [[UINavigationController alloc] initWithRootViewController:content];
childNavController.toolbarHidden = NO;
childNavController.view.frame = content.view.frame;
[self addChildViewController:childNavController];
[recorderView addSubview:childNavController.view];
[childNavController didMoveToParentViewController:self];
}
I've a bunch of turn based games in my app, and I use the same animations to declare the starting player.
At the very end of viewDidLoad, I placed the code for declaration. It takes the screenshot of current view then blurs it a little, and labels appear to show the name of the starting player. The issue is sometimes it happens to fast that I got the screenshot of previous view and labels appear on the blurred screenshot of previous view.
My viewDidLoad looks like this:
-(void) viewDidLoad
{
[super viewDidLoad];
[self initializeThings];
[self layoutUI]; //In some of the games this part requires heavy processing,
//ie laying out a 2D array of buttons (20x20=400 of them)
[self showStartingPlayer];
}
I use the default transition style cover vertical in all VCs. I tried calling [self showStartingPlayer]; deferred by using performSelector with delay but different devices require different delay values so it is not a robust solution. Is there any other method I can use in viewcontroller lifecycle instead of viewDidLoad or any practical way of doing such a thing?
if you are using presentViewController: animated: completion:, i would take advantage of the completion block to notify the view controller that the transition is complete.
for example, you could add a public method called -(void)wasJustPresented to your view controller which calls the necessary UI layout.
Then, call this in your completion block. Ex:
[self presentViewController:newVC
animated:YES
completion:^(void){
[newVC wasJustPresented];
}];
This will ensure your view controller is notified right after it is done being presented.
viewDidLoad is called when the view of the view controller has been loaded, but it doesn't mean that it's actually visible on the screen.
You may use - (void) viewDidAppear: to do that.
You should try to call your method inside the viewDidAppear which is called as the view transition has finished.
-(void)viewDidAppear:animated
{
[super viewDidAppear:animated];
//put your call here
}