in MyAppDelegate, when a button is pressed it presents a modal view:
- (void) showInfoPanel:(id)sender {
infoViewController = [[InfoViewController alloc] init];
UINavigationController *infoNavController = [[UINavigationController alloc] init];
infoNavController.navigationBarHidden = YES;
[window addSubview:infoNavController.view];
[infoNavController presentModalViewController:infoViewController animated:YES];
}
in InfoViewController i have to dismiss the modal view:
- (void) exitInfoPanel:(id)sender {
[self.parentViewController dismissModalViewControllerAnimated:YES];
}
although it works, the MyAppDelegate window doesn't respond to touches anymore.
instead in the InfoViewController if:
[self.view removeFromSuperview];
It respond to touches but I lose the animation of dismissing the modal view.
What I am doing wrong, why it doesn't respond to touches when the modalview is dismissed? ?
thanks
Related
I have a viewcontroller (vc1) in which I added another viewcontroller (vc2) as a subview. An UITapGestureRecognizer is triggered when you tap on a view (tappingView) contained in the subview (vc2). I would like to handle this tap inside the subview controller (vc2), and not from the first viewcontroller (vc1)... but it keeps crashing when I click on my view.
Here is the hierarchy sum up :
-vc1
--vc2
---tappingView
And here is a sample of code :
ViewController1 (viewDidLoad):
- (void)viewDidLoad
{
ViewController2 *vc2 = [[ViewController2 alloc] init];
[[self view] addSubview:[vc2 view]];
}
ViewController2 (viewDidLoad):
- (void)viewDidLoad
{
UIView *tappingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 60.0, 80.0)];
[[self view] addSubview:tappingView];
UITapGestureRecognizer *tapGestureRecognize = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureRecognizer:)];
[tappingView addGestureRecognizer:tapGestureRecognize];
}
ViewController2 (singleTapeGestureRecognizer:) :
- (void)singleTapGestureRecognizer:(id)sender {
NSLog(#"Tap gesture");
}
When I click in my view (tappingView), I keep getting a crash (BAD_ACCESS).
Anyone have an idea why ?
You shouldn't just add another view controller's view to your view -- you should make that controller a childViewController of vc1. Change the viewDidLoad in vc1 to this:
- (void)viewDidLoad {
ViewController2 *vc2 = [[ViewController2 alloc] init];
[self addChildViewController:vc2];
[vc2 didMoveToParentViewController:self];
[[self view] addSubview:[vc2 view]];
}
It's not clear why you're doing it this way in the first place. Why not present vc2 as a modal view controller instead?
In this block
- (void)viewDidLoad
{
ViewController2 *vc2 = [[ViewController2 alloc] init];
[[self view] addSubview:[vc2 view]];
}
your ViewController2 is not retained (addSubview only retains the view, not the view controller).
To fix it, declare vc2 as a strong property, instead of a variable.
self.vc2 = [[ViewController2 alloc] init];
Or better, as someone suggested, add vc2 as a child view controller.
Targets of UITapGestureRecognizer take the UIGestureRecognizer argument, not id. I.e.:
- (void)singleTapGestureRecognizer:(UIGestureRecognizer *)sender {
NSLog(#"Tap gesture");
}
Further, you're setting frames in viewDidLoad, which you should do in viewWillAppear: instead.
use below code
- (void)singleTapGestureRecognizer:(UIGestureRecognizer *)sender
instead of
- (void)singleTapGestureRecognizer:(id)sender.
As it must have UIGestureREcognizer instead of id.`
I have programatically created a TabBarController with views etc. Now i want to show this TabBarController on Button Press. How do i do that? Currently i am presenting it modally but it doesn't work - throws sigtrap errors.
This is my code for the TabBarController
#implementation TabBarViewController
- (void) loadView
{
HomeViewController * homeViewController = [[HomeViewController alloc]initWithNibName:#"HomeViewController" bundle:nil];
UITabBarController *tabBarController = [[UITabBarController alloc] init];
tabBarController.view.frame = CGRectMake(0, 0, 320, 460);
// Set each tab to show an appropriate view controller
[tabBarController setViewControllers:[NSArray arrayWithObjects:homeViewController, homeViewController, nil]];
[self.view addSubview:tabBarController.view];
[homeViewController release];
[tabBarController release];
}
This is my code for accessing this tabBarController from a Button Press event from my mainViewController -
- (IBAction)quickBrowse:(UIButton *)sender
{
TabBarViewController * tabBarController = [[TabBarViewController alloc]init];
[self presentModalViewController:tabBarController animated:YES];
[tabBarController release];
}
You should only override the method loadView if you are not using IB and if you want to create yours view manually. And when you do that you must assign your root view to the view property of UIViewController.
I believe in your case you don't need to override this method, you can use the viewDidLoad method to create your UITabBarController and store it in a variable, so when the event gets called all you need to do is pass the variable to the method presentModalViewController:animated:
Your final code would look like this:
- (void) viewDidLoad
{
[super viewDidLoad];
HomeViewController * homeViewController = [[HomeViewController alloc]initWithNibName:#"HomeViewController" bundle:nil];
// you can't pass the same view controller to more than one position in UITabBarController
HomeViewController * homeViewController2 = [[HomeViewController alloc]initWithNibName:#"HomeViewController" bundle:nil];
// local variable
self.modalTabBarController = [[UITabBarController alloc] init];
// Set each tab to show an appropriate view controller
[self.modalTabBarController setViewControllers:[NSArray arrayWithObjects:homeViewController, homeViewController2, nil]];
}
- (void)viewDidUnload
{
self.modalTabBarController = nil;
[super viewDidUnload];
}
- (IBAction)quickBrowse:(UIButton *)sender
{
[self presentModalViewController:self.modalTabBarController animated:YES];
}
I'd like to add a UINavigationController to my app info view (NOT to my main view). I've watched/read a number of tutorials showing how to add it to the main window through the AppDelegate using IB. In my case, I only want it to appear when a user presses the info button and is brought to the infoView. Here is how I switch to the infoView within my MainViewController:
- (IBAction)infoButtonPress:(id)sender
{
// Create pointer to instance of InfoViewController
InfoViewController *infoView = [[InfoViewController alloc] initWithNibName:#"InfoViewController" bundle:nil];
// Add view switching animation
infoView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
// Change view using animation
[self presentModalViewController:infoView animated:YES];
}
At this point the infoView is displayed and I would like THIS to be the RootView of the UINavigationController. I have tried adding the line:
UINavigationController *infoNavController = [[UINavigationController alloc]
initWithRootViewController:infoView];
after creating an instance of InfoViewController, but the app crashes. Is it possible to add UINavigationController to views other than the main view?
Thanks.
You are very close with your implementation. Try it in this order.
InfoViewController *infoView = [[InfoViewController alloc] initWithNibName:#"InfoViewController" bundle:nil];
UINavigationController *infoNavController = [[UINavigationController alloc]
initWithRootViewController:infoView];
[infoView release]; // skip this if using ARC
infoView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:infoNavController animated:YES];
UPDATE
To kill this modal, you will have to add your buttons to the main modal view.
InfoViewController.m
-(void)cancel:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
-(void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *cancelButton =
[[UIBarButtonItem alloc] initWithTitle: #"Cancel"
style: UIBarButtonItemStylePlain
target: self
action: #selector(cancel:)];
self.navigationItem.leftBarButtonItem = cancelButton;
[cancelButton release];
}
- (void)cancel {
// What should I do here?
}
// root view controller
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(cancel)];
self.navigationItem.leftBarButtonItem = cancelButton;
[cancelButton release];
}
I added cancel button in the navigation bar.
I want to go back to the previous view from root view when cancel button is pressed.
What do I have to do in cancel? I added root view controller like this.
RootController *rootController = [[RootController alloc]initWithStyle:UITableViewStylePlain];
UINavigationController *aNavigationController = [[UINavigationController alloc]initWithRootViewController:rootController];
self.naviController = aNavigationController;
[aNavigationController release];
[rootController release];
[self.view addSubview:[naviController view]];
You can pop the view.
[self.navigationController popViewControllerAnimated:YES];
You can dismiss it as well.
dismissModalViewcontrollerAnimated
EDIT:
If you are adding the view then you need to remove your view.
[self.view removeFromSuperView];
If you used a navigationController to push the view you can make use of popViewController: animated: method. If you presented the view as a modal view you can make use of dismissModalViewcontrollerAnimated: method
It seems you are not pushing or presenting the aNavigationController. You are just adding it as a subview. Neither popViewController nor dismissModalViewController won't work here. You have to just remove it from its superView. Try this.
- (void)cancel {
[self.view removeFromSuperView];
}
Add This.
[self.view removeFromSuperview]
Im my application I have the following code, the first bit runs when my application launches, and it presents a login screen in a modal view. With my rootController added to the window before that.
The Modal view will allow a user to log on, view terms and conditions and then if they accept the loadMainApp function is called.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
rootController.delegate = self;
[window addSubview:rootController.view];
LoginViewController *_loginViewController = [[LoginViewController alloc] initWithNibName:#"LoginView" bundle:[NSBundle mainBundle]];
self.loginViewController = _loginViewController;
[_loginViewController release];
UINavigationController *navi = [[[UINavigationController alloc]initWithRootViewController:loginViewController]autorelease];
navi.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[loginViewController release];
[rootController presentModalViewController:navi animated:YES];
[self.window makeKeyAndVisible];
return YES;
}
This next bit is called when the user accepts terms and conditions:
-(void)loadMainApp:(UIView *)fromView{
[fromView removeFromSuperview];
[window addSubview:rootController.view];
rootController.selectedIndex = 2;
rootController.delegate = self;
}
From here I want to be able to use the people picker which is a modal view and I attempt it with this code:
ABPeoplePickerNavigationController *picker =
[[ABPeoplePickerNavigationController alloc]init];
picker.peoplePickerDelegate = self;
[rootController presentModalViewController:picker animated:YES];
[picker release];
But nothing happens, when I try to present a modal view from my rootController nothing displays.
This appears to occur after this code in applicationDidFinishLaunching is run:
LoginViewController *_loginViewController = [[LoginViewController alloc] initWithNibName:#"LoginView" bundle:[NSBundle mainBundle]];
self.loginViewController = _loginViewController;
[_loginViewController release];
UINavigationController *navi = [[[UINavigationController alloc]initWithRootViewController:loginViewController]autorelease];
navi.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[loginViewController release];
[rootController presentModalViewController:navi animated:YES];
[self.window makeKeyAndVisible];
return YES;
If I dont display the login screen at all and instead just add my rootController
rootController.delegate = self;
[window addSubview:rootController.view];
in the applicationDidFinishLaunching function then everything works fine when I go to display the people picker.
Is there something fundamental that I am breaking here or can anyone spot what I may be doing wrong?
Are you dismissing the first modal view controller correctly, via thedismissModalViewControllerAnimated: method? If you're just removing the modal view controller's view from its superview, then probably a lot of paperwork is being left undone by UIKit.
What you should really do is something like this:
Add rootViewController to navigationController. Then add navigationController to the window.
In rootViewController's viewDidLoad method, set loginViewController's delegate to rootViewController and display the LoginViewController's instance as a modal.
When you are done with terms acceptance, do [delegate loginViewControllerFinished];.
Now in rootViewController, handle the loginViewControllerFinished method. This should contain a call to [self dismissModalViewControllerAnimated:YES]; to close the login modal view. Then you should launch ABPeoplePickerNavigationController as a modal view.
In AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Make sure rootViewController is initiated by this point.
UINavigationController *navigationController = [[[UINavigationController alloc] initWithRootViewController:rootViewController] autorelease];
[window addSubview:rootController.view];
[self.window makeKeyAndVisible];
return YES;
}
In RootViewController:
- (void)viewDidLoad {
[super viewDidLoad];
LoginViewController *loginViewController = [[[LoginViewController alloc] initWithNibName:#"LoginView" bundle:nil] autorelease];
loginViewController.delegate = self;
loginViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:loginViewController animated:YES];
}
- (void)loginViewControllerFinished {
[self dismissModalViewControllerAnimated:YES];
// Here we are closing one modal. And showing another after that.
ABPeoplePickerNavigationController *peoplePicker = [[[ABPeoplePickerNavigationController alloc] init] autorelease];
peoplePicker.peoplePickerDelegate = self;
[self presentModalViewController:peoplePicker animated:YES];
}
In LoginViewController:
// Make sure LoginViewController has delegate property in header.
// #property (nonatomic, assign) id delegate;
// And put this in implementation (.m) file. #synthesize delegate.
// Don't put release for delegate, since it's not retained. It's only 'assigned'.
- (void)done {
// Call this when you want to close loginViewController.
[delegate loginViewControllerFinished];
}
Hope this helps.