I have two views with their controllers.
The application start with the FirstViewController.
Then with a button I open the SecondViewController.
With other button I dismiss the SecondViewController to return to FirstViewController.
Is there any way to detect that in FirstViewController that it has recovered focus?
EDIT: Ok I look the answers and I use viewWillAppear but don't work if I use a UIModalPresentationFormSheet.
-(IBAction)openSecondView{
SecondViewController *screen = [[SecondViewController alloc] initWithNibName:nil bundle:nil];
screen.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
screen.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:screen animated:YES];
[screen release];
}
And close this view with close button.
viewWillAppear never called.
implement UIViewController's viewWillAppear method
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
}
Add a delegate (Protocol) method. Call the delegate method just before dismissing the SecondViewController.
For more info on delegate, see delegate
implementation of the viewWillAppear: callback will work only if you use navigation controller or tabbarcontroller for displaying another controller + with such approach you will need to check somehow if this is only the first appearance of the view, or was called by any other reason;
using a delegate, as described by Gomathi above is a much better option!
Depends how you are setting up the first view controller. Encapsulate it within UINavigationViewController (and if you do not want the navigation bar, you can always set it to hidden ( [self.navigationController.navigationBar setHidden:YES] ). ViewWillAppear will work then.
inside the viewWillAppear of the FirstViewController
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSLog(#"view 1 focused");
}
Related
I am trying to open a modalview from a view like that,
SignupViewController *signUpView = [[SignupViewController alloc] initWithNibName:#"SignupViewController" bundle:nil];
[signUpView setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
self.parentViewController.view.transform = CGAffineTransformMakeScale(1.3, 1.3);
self.parentViewController.view.alpha = 0;
[UIView animateWithDuration:.35 animations:^{self.parentViewController.view.alpha = 1.0; self.parentViewController.view.transform = CGAffineTransformMakeScale(1, 1);}];
[self presentModalViewController:signUpView animated:YES];
After login i am closing the modalview and redirecting to anther view, but the parentview is still there,
[self dismissViewControllerAnimated:YES completion:^{
ToolsViewController *gototoolpage = [[ToolsViewController alloc] initWithNibName:#"ToolsViewController" bundle:nil];
[self.navigationController pushViewController:gototoolpage animated:YES];
}
How to dismiss the parentview also. Any idea
You code looks a little confused. What do you intend by references to parentViewController? Check the docs - it is the containing viewController, not the previous or presenting viewController. In a NavigationController context this would be the UINavigationController. In a modal view context there is no parentViewController, but there is a presenting ViewController. I am not sure what you intend by all of those calls to self.parentViewController.
In any case you should really be sending the dismiss request back to your presenting viewController via a delegate so that it is completely clear where the pushViewController message is being passed from and to.
In the header file of your signUpViewController declare a protocol:
#protocol SignUpViewControllerDelegate
- (void) dissmissSignUpVC;
#end
then in your presentingViewController, after
SignupViewController *signUpView = [[SignupViewController alloc] initWithNibName:#"SignupViewController" bundle:nil];
add
[signUpView setDelegate:self];
and implement the delegate method with the same code you now have in your completion block:
- (void) dissmissSignUpVC {
ToolsViewController *gototoolpage = [[ToolsViewController alloc]
initWithNibName:#"ToolsViewController" bundle:nil];
[self.navigationController pushViewController:gototoolpage animated:YES];
}
In signUpView invoke the delegate's method to dismiss:
[[self delegate] dissmissSignUpVC];
Watch out for those stacked animations, I suspect that only the first will be performed (i.e. gototollpage animated:YES might as well be gototoolpage animated:NO)
Perhaps anyway you should reconsider your logic. I imagine the user might have a confusing experience if you do this under-the-hood manipulation of viewControllers. Better that there is a UI control for the user to navigate to toolsViewController so they understand where they are?
I'm building an app that currently has 3 ViewControllers. One of them is used after a successful login so is not relevant in this question.
I'm using a mixture of Storyboards and building things programmatically when I find Storyboards do not give me the fine control that I need.
The first ViewController is built in my 'MainStoryboard'. It has a login form and an info button at the bottom. I link it up the my AppDelegate by doing the following inside didFinishLaunchingWithOptions:
ViewController *viewController = (ViewController *)self.window.rootViewController;
Because I wanted to force rendering of a UIWebView (another story) I create the second view programmatically. I do the following inside didFinishLaunchingWithOptions:
infoViewController = [[InfoViewController alloc] init];
[infoViewController view];
Inside both of my ViewControllers I setup a link to appDelegate as below:
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
I have an info button in my first ViewController that takes you to the infoViewController. It calls the following code when tapped:
appDelegate.infoViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:appDelegate.infoViewController animated:YES];
The above works just fine for me, flips over the screen and shows the InfoViewController.
On my InfoViewController I have a button that should take you back to the login page, I have tried all sorts to get this to work but it just crashes my app. Nothing seems to work. I have tried the following:
appDelegate.viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:appDelegate.viewController animated:YES];
and
[self.navigationController popToRootViewControllerAnimated:YES];
and
[self.navigationController popViewControllerAnimated:YES];
and
[self.navigationController popToViewController:appDelegate.viewController animated:YES];
I suspect the last 3 might be more to do with when you have a navigation view controller and you want to go back to the root? I'm not sure, but either way it does not work. I had this working using storyboards previously so I'm sure it ought to be easy! As mentioned I switched to making the infoViewController programmatically so that I could force the UIWebView to render before the view appeared.
Any help much appreciated.
You can do with:
[self dismissModalViewControllerAnimated:YES];
You should use this.
[self dismissModalViewControllerAnimated:YES];
You should use a main controller for switching between your other view controllers. Change the view of your root controller to one of your other view controllers (apply animations as usual if needed). Hold a pointer to your root controller in your other view controllers and call self.rootController.view = <desired_controller_instance>.view
I think the way you're presenting your InfoViewController is wrong. Do it the following way:
In your ViewController, create an action for the info button.:
- (IBAction)infoButtonTapped:(id)sender
{
InfoViewController *infoViewController = [[InfoViewController alloc] init];
infoViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:infoViewController animated:YES];
}
And in your InfoViewController, in the action of your button that should take you back write this:
- (void)takeBackToViewController
{
[self dismissModalViewControllerAnimated:YES];
}
Hope it works.
Also in presented controller you can use this
if(self.parentViewController)
[self.parentViewController dismissModalViewControllerAnimated:YES];
else
[self.presentingViewController dismissModalViewControllerAnimated:YES];
To dissmiss current controller.
I have some uiview, one call another in this way:
From first uiview:
MyViewController *contr1 = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
[self.view addSubview:contr1.view];
From second uiview:
MyViewController2 *contr2 = [[MyViewController2 alloc] initWithNibName:#"MyViewController2" bundle:nil];
[self.view addSubview:contr2.view];
now in the third uiview i want to return back on the first updating it ( calling viewDidLoad ). how can i do?
First of all - you are doing it wrong.
Since you are using view controllers present them modally or push them:
MyViewController2 *contr2 = [[MyViewController2 alloc] initWithNibName:#"MyViewController2" bundle:nil];
[self presentModalViewController:contr2];
If you want to dismiss modal controllers exactly to your root view controller you should obtain a pointer to it in the controller you are currently using and send it a message to dismiss every modal view that there is on it.
- (IBAction)doHomePage:(id)sender {
MyAppDelegate *appDelegate = (MyAppDelegate *)[UIApplication sharedApplication].delegate;
[appDelegate.navigationController.rootViewController dismissModalViewControllerAnimated:YES];
}
Also instead of viewDidLoad: you might want to use viewWillAppear: or viewDidAppear:.
Sorry beforehand if there are some typo errors in the code since I wrote it by hand.
My RootViewController is a UITableViewController. A UINavigationController is added programmatically:
_navigationController = [[[UINavigationController alloc] initWithRootViewController:_rootViewController] autorelease];
[self.window addSubview:_navigationController.view];
[self.window makeKeyAndVisible];
Within the RootViewController.m the DetailViewController should be loaded when a row is selected:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Switch to detail");
CCouchDBDocument *selectedObject = [self.contentsList objectAtIndex:indexPath.row];
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
[self.view addSubview:detailViewController.view];
[detailViewController setDetailItem: selectedObject];
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
Without addSubView nothing happens on the screen. All the examples I've seen before only use pushViewController. And, loading the DetailView takes about 4 seconds. That's way too long (it's currently empty, just one label). When I try to set the navigationTitle (self.title = #"Hello";), the title remains the same from the RootViewController, so something must be wrong with the navigationController.
I tried to put everything in the AppDelegate and use a switchView method. The problem is the call for setDetailItem, which I can't call if I work with the switch method.
What would be the correct way to load the DetailView from the RootViewController into the navigation stack and possibly more from the DetailViewController later?
Update
I started from the beginning again with a Window-based application. Added a UITableViewController as "RootViewController" and initialised it with the UINavigationController in the AppDelegate (did absolutely nothing in the XIB). When I try to set self.navigationController.title = #"Test"; in ViewDidLoad, nothing happens.
What's wrong there?
You don't set the title of the DetailView when it's displayed using a UINavigationController by using self.title, you need to set the UINavigationItem title property in the DetailView initializer.
e.g. in the DetailView initializer :-
self.navigationItem.title = #"Hello";
You're right you shouldn't need to add the detailViewController view as a subview of the current view - you should just need the pushViewController call. I'm not sure why it's not appearing though.
Obvious questions are is everything connected OK in the nib, and what does the DetailView initializer do?
I have MainMenuViewController with button which action is
- (IBAction) goToFirstView {
FirstViewController *fvc = [[FirstViewController alloc] init];
[self.view addSubview:fvc.view];
[fvc release];
}
FirstViewController have UIButton with action
- (IBAction) rightArrow {
SecondViewController *svc = [[SecondViewController alloc] init];
[self.view addSubview:svc.view];
[svc release];
}
But when I press "rightArrow" button app crashes with "EXC_BAD_ACCESS". Can't found my problem. Help me please.
[svc release];
The problem is here. When releasing the view controller, the view's events will target a freed object, and make your program crash (probably in viewDidLoad or viewDidAppear if it's instant but it doesn't matter). Note that a view does not (normally, AFAIK) retain it's view controller, if that might have been your assumption...
When you say [self.view addSubview:svc.view] you're adding SecondViewController's view to FirstViewController's view. Similar with MainViewController and FirstViewController. What you'll end up with is a view hierarchy that looks like this:
main view
first view
second view
I doubt that's really what you want. Instead, use a navigation controller with your MainViewController as the nav controller's root controller, and then use -pushViewController:animated: to push the controllers (not the views!) onto the navigation stack.