Allowing autorotation inside a programmatically created view that is displayed modally - iphone

This has been asked a dozen times on this site, but I haven't found an answer that works for me. I have an iPad application with a UISplitViewController on the root level that is created programmatically. Inside the view that is being displayed in the right hand pane, triggered by user interaction, a UINavigationController is programmatically created and presented to the user. Here is that code:
listenerController = [[UINavigationController alloc] initWithRootViewController:listenerView];
[listenerController.navigationBar setTintColor:[UIColor colorWithRed:185.0f/255.0f green:80.0f/255.0f blue:0.0f/255.0f alpha:1.0f]];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[listenerController setModalPresentationStyle:UIModalPresentationFormSheet];
[listenerController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[listenerController setModalInPopover:YES];
}
[self presentModalViewController:listenerController animated:YES];
[listenerController release];
This does create the view controller properly, but when it is displayed the iPad is forced back into portrait view regardless of what orientation I have the iPad in. Then when I dismiss the modal window, it will rotate back.
I already have shouldAutorotateToInterfaceOrientation in the viewcontroller of the righthand pane set to YES, and I even tried adding this to the main app delegate class without any luck. It doesn't seem like I should have to subclass UINavigationController just to override the shouldAutorotateToInterfaceOrientation method.
Am I calling presentModalViewController from the wrong object? I've tried [self presentModalViewController ...] as well as [self.parentViewController presentModalViewController ...] with the same results.

I'm assuming that the self in your code example is the right-view (detail) view controller. You need to call presentModalViewController from the root UISplitViewController.

Related

Trigger a seque from the AppDelegate to popup a view in the StoryBoard

I am trying to convert my App to a Storyboard, but am having some problems.
In de previous model I could have an 'actionClass' in my AppDelegate which I called when I needed to pop-up a view.
E.g.
DOArticleViewController *articleView = [[DOArticleViewController alloc] initWithArticle:article notification: notification nibName:#"DOArticleViewController" bundle:nil];
[[self navigationController] pushViewController:articleView animated:YES];
But now with the storyboard it does not work anymore.
Then I tried the following code in the AppDelegate:
id currentController = [[[[self window] rootViewController] navigationController] visibleViewController];
[currentController performSegueWithIdentifier:#"settingsSeque" sender:nil];
Don;t think this is the best anyway, as only the rootViewController has all the seques needed, and might not be the visibleViewController, but one step at a time.
With this the only thing I see happening is the message and no action:
Unbalanced calls to begin/end appearance transitions for UINavigationController: 0xb428e00.
I spend a view hours now on trying to figure out to get this to work, but am realising that it might be better to go back to the traditional independent XIB files....
I solved with the answer given in this question: ios: Accessing a navigation controller from app delegate
I tried to get the Navigation Controller, but this was nil and I didn't realise it.
My navigation controller was the rootViewController, so that is also the NavigationController.
Casting the rootViewController to NavigationController and invoking 'visibleViewController' worked fine after that!

UIViewController displayed behind current view when presented modally

On iOS 5, when I try to present any view controller from another one, using presentModalViewController, the modal view is presented behind the current view.
Since it works fine on iOS 4 and knowing that presentModalViewController has been deprecated in iOS 5, I tried using presentViewController with no luck.
This is the first time I encounter this issue, any ideas on what could lead to this weird behavior?
I believe the issue is that you have not set a proper modal presentation style.
http://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/Reference/Reference.html#//apple_ref/doc/c_ref/UIModalPresentationStyle
This sample should trigger a full screen modal over top of your existing view controller.
[self setModalPresentationStyle:UIModalPresentationFullScreen];
ViewController2 *vc = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
[self presentViewController:vc animated:YES completion:NULL];
Not sure if you're using a button to present the view controller, but this should work if you are. Create a new function in your view controller like the one below. This instantiates your view and a navigation controller in your view so it can be dismissed afterwards.
- (void)buttonPressed {
UIViewController *yourViewController = [[UIViewController alloc] initWithNibName:nil bundle:nil];
UINavigationController *navigationController = [[UINavigationController] alloc] initWithRootViewController:yourViewController];
[self presentModalViewController:navigationController animated:YES];
}
And then in viewDidLoad you'd have something like this (if you were presenting it from a button). The code below is for a UIBarButtonItem, but other buttons should work in a similar manner. Just make sure you set the action parameter to #selector(buttonPressed), or whatever the name of the function you want called when the button is pressed.
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] init]
target:self
action:#selector(buttonPressed)];
I have finally found the issue. For some awkward reasons, the rootViewController of the root window wasn't set properly, leading to strange behaviors with modal views.
What is the more puzzling is that it worked fine on iOS 4 so far and failed on iOS 5. I believe I'm still missing the true reasons leading to such trouble, but correctly setting the rootViewController in AppDelegate solved the problem.

Unable to get presentViewController to work

I copied a working viewcontroller class from another project into a new project. I can't get the view to load in the new project. In the old project I used presentModalViewController. In the new I cannot get the view to load using either presentModalViewController or presentViewController
I am trying to load the present the view from my main view controller.
Here is what my main view controller interface looks like...
// ViewController.h
#import <UIKit/UIKit.h>
#import "RequestDialogViewController.h"
#interface ViewController : UIViewController <RequestDialogViewControllerDelegate> {
}
- (void)requestDialogViewDidDismiss:(RequestDialogViewController *)controller withResponse:(NSString*)response;
I am using presentModalViewController like this...
RequestDialogViewController *requestIPViewController = [[RequestDialogViewController alloc] initWithNibName:#"RequestDialogViewController" bundle:nil];
navigationController = [[UINavigationController alloc] initWithRootViewController:requestIPViewController];
[self presentModalViewController:navigationController animated:YES];
and presentViewController like this...
RequestDialogViewController *requestIPViewController = [[RequestDialogViewController alloc] initWithNibName:#"RequestDialogViewController" bundle:nil];
[self presentViewController:requestIPViewController animated:YES completion:nil];
What am I missing in the new project? The init method fires, but viewDidLoad does not and nothing is displayed.
Thanks
If ViewController is the root view controller, it can't present a modal view controller from within its own viewDidLoad, because at that point it doesn't have information like the screen size.
If other view controllers have already displayed, this will work. If the root view controller is a UINavigationController, you will see a view sliding in from the right while the modal view slides up from the bottom.
Anyway, for your ViewController, the soonest you could present it is after it has become visible. Using a timer for this is unreliable; older and slower devices have dramatically longer load times.
For more reliability, implement viewDidAppear: for ViewController. Do still use your timer system to add an additional delay; a fraction of a second should be sufficient. Although presenting the modal view controller from within viewDidAppear worked for me in the iOS 5.1 simulator, Presenting a modal view controller when loading another ViewController says it sometimes doesn't happen.
I have it resolved. I was trying to present the view from view did load of the main view controller. Not sure why it does not work there, but instead I am now setting a timer which calls a method to present the view controller after the main view loads and it works fine now using...
[self presentViewController:requestIPViewController animated:YES completion:nil];
Thanks to those who replied.
As #Dondragmer said, if you want to present your viewController in root view's viewDidLoad, it will fail.Once your viewController is ready for that, you can present your new viewController.
So, you can do that in
- (void)viewDidLayoutSubviews {
//present here
}
I encountered the same problem. But my situation is the presentViewController is called after the dismissViewControllerAnimated for another ViewController. My solution is to move the presentViewController to completion block of dismissViewControllerAnimated.
Present a modalViewController:
For the benefit of all starting programmers, type it instead of copy paste.
myVC *viewController = [[myVC alloc]initWithNibName:#"myVC" bundle:nil];
viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:viewController animated:YES];
[viewController release];
It looks like you were trying to present a nav controller as a view controller in the first sample, then you were using the wrong method in the second one.

InterfaceOrientation issues when popping a ViewController off the stack

I have the beginnings of my app working pretty well but I have one small issue that I can't figure out how to fix.
It's a view based app and I have a NavigationController in my appDelegate file which is pushing various ViewControllers as required. Going in the "forwards direction" everything works well, seems perfect actually, but the problem I have is when VC's are popped off the stack. This is the code I'm using to show the VC and then just using the back button to go back.
UINavigationController *iaxNC = [[UINavigationController alloc] init];
LogInViewController *logInVC = [[LogInViewController alloc] init];
[iaxNC pushViewController:logInVC animated:NO];
[logInVC release];
[_window addSubview:iaxNC.view];
[_window makeKeyAndVisible];
That loads my login view and then the code checks to see if there are any users before it loads the SetUp screen (if there are none) as follows:
setUpVC = [[SetUpViewController alloc] init];
setUpVC.firstUse = self.firstUse;
[self.navigationController pushViewController:setUpVC animated:YES];
[setUpVC release];
The problem happens when I hit the back button from the SetUp view to go back to the LogIn view.
I have a portrait and a landscape view for most of the VC's and these VC's are subclasses of Michael Tyson's TPMultiLayoutViewController. The portrait view is hooked up as *portraitView and also as *view, the landscape view is hooked up as *landscapeView.
The problem is this:
If I push a VC into view and change the orientation of the device before I hit the back button then when I do hit "Back" the previous VC is displayed in its original format (i.e. NOT rotated to the current orientation) it also appears that the lower left corner of the view is in the lower left of the screen. It then "sticks" like that until I rotate the device again and then all is good and functions as expected.
So the thing is I'm working through the contents of the TPMultiView subclass but I don't pretend to understand all of it yet (and therein probably lies my REAL problem) but as a stopgap solution is there a way to force the view of the "pusher" VC to appear in it's previous orientation (albeit briefly - and THEN allow it to rotate once it has been displayed) when the "pushee's" VC is popped?
Does that make sense?
SOLVED IT! The problem was I had included my own viewWillAppear method in LogInVC but I hadn't called [super viewWillAppear] so the effect of the superclass was never really going to work, was it! Thanks for the input. I can recommend the TPMultiView drop in subclass BTW works very nicely.
You should first verify your implementation of shouldAutoRotateToInterfaceOrientation: is correct for all your view controllers.
Then make sure the views of your view controller's have an appropriate autoresizingMask set. If you have created the view controllers and their views in Interface Builder you should set the resizing mask there.
Otherwise in your -loadView or -viewDidLoad methods you should have this line:
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;

Adding a subview into view hierarchy

I'd like to have a view appear when the user clicks a button. The hierarchy I have looks like this:
MainWindow
-UIView
--ScrollView
---ScrollView.pages = UIViews
----UIView (from above assignment)
----TextView
----InfoButton
pages is an NSMutableArry of pageController objects. These hook to a nib. These nibs are the pages that user flicks through in the scroll view.
The InfoButton click is wired up like this:
- (IBAction) infoButton_click:(id)sender{
topView topViewViewController *topView = [[topViewViewController alloc] initWithNibName:#"TopView" bundle:[NSBundle mainBundle]];
//[self.navigationController pushViewController: topViewView animated:YES];
//[self.view addSubview: topViewView.view];
[super.view addSubview: topViewView.view];
[topViewView release];
}
InfoButton is on one of the pages in the ScrollView. I've commented out different code that has been tried. None of it adds the view. Nothing happens. Is there a way to get TopView as the top view in the hierarchy?
Is your goal to add the view as a subview, or to slide on a new view using the navigation controller? I'm going to assume the latter for the moment.
- (IBAction)infoButton_click:(id)sender
{
TopViewController *topViewController = [[TopViewController alloc] initWithNibName:#"TopView" bundle:nil];
[self.navigationController pushViewController:topViewController animated:YES];
[topViewController release];
}
This is correct if you actually have a navigationController. Make sure you actually do. When "nothing happens" in Cocoa, it usually means something is nil. You should check in the debugger or with NSLog() to see if any of these values are nil. It is possible (even likely), that your parent has a navigationController, but you do not.
Classes should always have a leading capital. Do not create a variable called "view" that is of class "UIViewController". This is a sure path to suffering. Objective-C is a dynamic language with limited compiler checks on types. Naming things correctly is critical to effective programming in ObjC.
Based on your comment to a previous answer, you want to present a modal view. You do this by creating a new view "modalView" and calling [topView presentModalViewController:modalView animated:YES].
In a future version of the iPhone OS, which of course I would be unable to comment upon if it were under NDA, you might be able to present a modal view controller with a flip transition by setting a property on the view controller to be presented, which would probably be called modalTransitionStyle or somesuch.