How to pop to rootViewController from SKScene?
im trying to build a game with menu screen.
There are two scenes - one for menu and one for game.
I have problem with jumping to rootView from a game scene.
Game scene has SKScene with menu button - SKLabelNode.
When touched it should move player to menu screen.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
SKNode *touched = [self nodeAtPoint:[touch locationInNode:self]];
if ([touched.name isEqualToString:BUTTON_MENU_NAME]) {
UIViewController *vc = self.view.window.rootViewController;
[vc.navigationController popToRootViewControllerAnimated:YES];
}
}
Touch is detected correctly but nothing happens.
Probably the initial view controller is the navigation controller so I suggest doing:
UINavigationController *vc = (UINavigationController *)appdelegate.window.rootViewController;
[vc popToRootViewControllerAnimated:YES];
Related
I'm pretty new to iOS. I'm building an app and am running into an issue. I have a navigation controller with a table view controller atop its stack. When I select a row in that table view controller, what I'd like to see is a collection view with the following:
The nav bar with the name that appears on the selected cell as the navigation item title.
A collection view as the main interface
a tab bar with the collection view, and an imagePickerController
Here's what my code looks like:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NewTabBarController *tbc = [[NewTabBarController alloc] init];
UIImagePickerController *takeAPicture = [[UIImagePickerController alloc] init];
UITabBarItem *tabItem = [takeAPicture tabBarItem];
[tabItem setImage:[UIImage imageWithContentsOfFile:#"CameraIcon.jpg"]];
[tabItem setTitle:#"Take a photo!"];
UICollectionViewFlowLayout *photoFlow = [[UICollectionViewFlowLayout alloc] init];
PhotoCollectionViewController *photoHub = [[PhotoCollectionViewController alloc] initWithCollectionViewLayout:photoFlow];
[tbc setViewControllers:[NSArray arrayWithObjects:photoHub, takeAPicture, nil]];
NSArray *items = [[items accessor] allItems];
Item *item = [items objectAtIndex:[indexPath row]];
[photoHub setItem:item];
[photoHub useLayoutToLayoutNavigationTransitions];
[[self navigationController] pushViewController:tbc animated:YES];
}
Then in my PhotoCollectionViewController implementation I have:
#syntesize item;
- (void)viewDidLoad {
[super viewDidLoad];
UINavigationItem *itemHeader = [self navigationItem];
[itemHeader setTitle:[item itemName]];
UITabBarItem *tabItem = [self tabBarItem];
[tabItem setImage:[UIImage imageWithContentsOfFile:#"itemImage.jpg"]];
[tabItem setTitle:[NSString stringWithFormat:#"Photos of %#", [item itemName]]];
}
My problem is that when I select the cell, The collection view loads, and I can see the cells I have set up in the collection view, but the nav bar item has no title, and the tab bar item has "Photos of (null)" and no image. The "Take a photo!" text appears, but the image does not.
Do you guys have any idea how I can restructure this to make everything flow correctly. I must be doing something wrong in the way I'm utilizing tab and nav controllers.I don't want there to be any tabs until this stage in the app, which is 3 or 4 VCs in already. Should I be using a tab bar controller from the App Delegate onward?
The problem here is that you are pushing tab bar controller onto a navigation controller stack. The view controllers of a tab bar will have a navigation item, but their navigation items aren't shown when the view controller is on screen. Instead, the tab bar controller's navigation item is on screen.
You could use self.tabBarController.navigationItem, but then each view controller will have to modify the navigation item every time it's brought on/off screen, which is really messy.
If you're going to use a UITabBarController, I would recommend either presenting it modally, or having it be the root view controller on your UIWindow. It's tough to get it working right as a view controller in a navigation controller's view controller stack.
Your tab bar item not showing its name is a separate issue. It's because viewDidLoad is getting called before you set your item instance, specifically it's getting called when you call [tbc setViewControllers:[NSArray arrayWithObjects:photoHub, takeAPicture, nil]];
You can confirm this by breakpointing in view did load, where you'll see that item is nil. If you haven't already, you should overload your setItem: method in PhotoCollectionViewController, and have that method also update your UI.
I have a segue that works for iPhone code to present the contents of a tableViewController embedded in a Navigation controller.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UINavigationController *nc = (UINavigationController *)segue.destinationViewController;
tvc = (MyTableViewController *)[nc.viewControllers lastObject];
tvc.managedObjectContext = managedObjectContext;
}
tvc is a storyboard item, UITableViewController subclass, embedded in a navigationController. I am trying to find the easiest way to use the same setup on iPad, but present the contents in a popover, with a navigation controller, as opposed to presenting full screen as it's doing now. Else do I need to create a new viewController without using this setup?
I created a custom UIStoryboardPopoverSegue, with the following perform code:
- (void)perform
{
UITableViewController *src = (UITableViewController *) self.sourceViewController;
MyController *dst = (MyController *) self.destinationViewController;
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:dst];
UITableViewCell *cell = [src.tableView cellForRowAtIndexPath:[src.tableView indexPathForSelectedRow]];
UIPopoverController *pop = [[UIPopoverController alloc] initWithContentViewController:navigationController];
dst.popoverController = pop;
CGSize size = CGSizeMake(475, src.view.frame.size.height);
pop.popoverContentSize = size;
[pop presentPopoverFromRect:cell.frame
inView:src.tableView
permittedArrowDirections:UIPopoverArrowDirectionUp | UIPopoverArrowDirectionDown
animated:YES];
}
The downside of this is that it requires a seque that is custom to destination view controller. The upside is an easy to implement and support, well functioning popover segue.
I am trying to create a camera overlay that can recognize swipe gestures to push to other views.
I am wondering if I can still use the UIImagePicker or if I have to use the AVCaptureSessionManager.
Also i would prefer to create the overlay view in the story board is there a way to do that?
can I select a view inside the storyboard controller be the camera overlay and simply present the UIImagePicker on view did load?
I've never used the Storyboard to create a camera overlay, but I have created a xib which works fine. You can create the overlay viewController in the normal (xib) way, complete with gesture recognizers, then you can handle them directly in that VC or use a delegate (most likely the VC which presented the camera).
Some code -
-(void)setupCamera
{
self.picker = [[UIImagePickerController alloc] init];
_picker.sourceType = UIImagePickerControllerSourceTypeCamera;
_picker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
self.overlay = [[OverlayViewController alloc] init];
_overlay.delegate = self;
_picker.cameraOverlayView = _overlay.view;
_picker.delegate = self;
[self presentViewController:self.picker animated:YES completion:nil];
}
The overlay -
-(id)init
{
self = [super initWithNibName:#"OverlayViewController" bundle:nil];
if (self)
{
// set up stuff
}
return self;
}
... & some code which handles the swipe -
-(IBAction)swipe:(UISwipeGestureRecognizer *)sender
{
// swipe stuff
[self.delegate doSwipeStuff]; // if you want the delegate to handle it
}
Hope this helps.
I create a split view project, on the iPhone's storyboard, i drag a bar button item to the navigation right and change the style Add, and i drag a view controller to the storyboard, so i use control-drag to build the link, and change the uiviewcontroller's custom class "AddViewController", when i run the project and push the DetailViewController, it is black view.
And i have input the code on the AddViewController.m
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"AddViewController"];
[vc setModalPresentationStyle:UIModalPresentationCurrentContext];
[self presentModalViewController:vc animated:YES];
}
i found the reason
On the my create "AddCreateViewController", i should comment the function.
- (void)loadView
{
// If you create your views manually, you MUST override this method and use it to create your views.
// If you use Interface Builder to create your views, then you must NOT override this method.
}
I am stuck trying to customize UINavigationController's backbutton.
In RootViewController I set self.title in viewDidLoad, and this string appears in Navigation Bar. In -didSelectRowAtIndexPath I create child view controller, configure back button and call -pushViewController. Processing for child will push child viewcontrollers onto the stack; I need back button to pop to initial view, just as when going back from first child view controller. Currenty backbutton will pop to prior view, so if there are 5 child view controllers on the stack, I have to hit back button 5 times to get to root view.
I am unable to get action to fire off when back button is displayed. I am able to popToRootViewController when in child VC; however, backbutton now appears on root view(!) and I have to hit backbutton once more to restore original title and remove backbutton.
Here is part of root -viewDidLoad:
- (void)viewDidLoad {
self.title = #"My Nav Bar Title"; // displays on root navigation bar title
// some setup code...
[super viewDidLoad];
}
Here is part of -didSelectRowAtIndexPath, where selecting a tableview cell results in child view being pushed onto stack:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
ChildVC *child = [[ChildVC alloc]
initWithNibName:#"Child"
bundle:nil];
[self.navigationController dismissModalViewControllerAnimated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Quiz" style:UIBarButtonItemStylePlain target:self action:#selector(backToMenu)];
self.navigationItem.backBarButtonItem = backButton;
[backButton release];
[self.navigationController pushViewController:child
animated:YES];
[child release];
}
Here is action method which doesn't fire when backbutton is pressed:
-(void)backToMenu {
NSLog(#" in root backToMenu");
[self.navigationController popViewControllerAnimated:YES];
}
ChildVC will also create a new child in its -didSelectRowAtIndexPath and push the new child controller, as the next child 'page':
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Child *newChild = [[Child alloc]
initWithNibName:#"Child"
bundle:nil];
[self.navigationController dismissModalViewControllerAnimated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
self.title = self.quizString; // child view correctly displays customized title
UIBarButtonItem *backButton = [[UIBarButtonItem alloc]
initWithTitle:#"Quiz"
style:UIBarButtonItemStylePlain
target:self
action:#selector(backToMenu)];
self.navigationItem.backBarButtonItem = backButton;
[backButton release];
[self.navigationController pushViewController:newQuestion
animated:YES];
[newChild release];
}
In Child -viewWillDisappear I set a global variable so I known when to push new child and when to pop back to root:
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:YES];
if (startOver) {
[self backToMenu];
}
}
Child -backToMenu:
-(void)backToMenu {
[self.navigationController popToRootViewControllerAnimated:YES];
}
Here is the sequence when back button is pressed in Child:
-- Child -viewWillDisappear is invoked, calls -backToMenu
-- -backToMenu calls popToRootViewControllerAnimated:
-- Child -viewWillDisappear is invoked again, calls -backToMenu
-- root -viewWillAppear is invoked
-- control returns to Child -backToMenu
Root view appears correctly, but Nav bar contains back button and title just like it still was a Child view. Pressing back button removes back button an restores original title.
How can I make this work? Ideally I would like to only have 1 child view on the stack, but I can't figure out how; then the back button would go back to root view. But when I tried this, I got NSInvalidArgumentException', reason: 'Pushing the same view controller instance more than once is not supported...'
Also, anything obvious why action is not fired when backbutton is pressed? Any help is GREATLY appreciated...thx
UIBarButtonItem *btnBack=[[UIBarButtonItem alloc]initWithTitle:#"" style:UIBarButtonItemStyleDone target:self action:#selector(back:)] ;
self.navigationItem.leftBarButtonItem=btnBack;
//Add image on back button
UIImage *backButtonImage = [[UIImage imageNamed:#"btn_back.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 13, 0, 6)];
[btnBack setBackgroundImage:backButtonImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
put this code in your view controller[initWithNibName method]form where you want to pop at root view controller
- (void) back : (id)sender
{
[self.navigationController popToRootViewControllerAnimated:YES];
}
uhm, your backButton calls popToRootViewController, which calls viewWillDissapear, which, if startOver is true calls popToRootViewController AGAIN?
what happens if it's false anyway? it continues the popToRootViewController called earlier ...
backButton->popToRoot->viewWillDissapear->check startOver
->YES->popToRoot->viewWillDissapear again->check startOver again->??
->NO->continue the disappearing of the view that was called also by popToRoot
isn't that if there redundant, since both it's branches continue previously popToRoot or call popToRoot again?
why not test for startOver first(in your backToMenu), then popToRootViewController if true?