In my iOS 7/8 app, I have several viewcontrollers all of which should be portrait. I have a view controller which has a full screen view which will play video. I need this view to able to rotate depending on orientation of the phone. However the view controller that contains the video view is not allowed to rotate, reason being there are some other views sometimes overlaid above the full screen video view that are part of the viewcontroller and these should not be rotated.
So how can I rotate a single view and how do I get informed that the orientation of the device has changed. The usual [UIApplication sharedApplication].statusBarOrientation doesn't work as the viewcontroller itself does not rotate.
How to solve this problem.
Thanks
You can't rotate the screen forcefully. There is another way, in your case you have all the screens in Portrait, and you need a ViewController which can rotate both ways. You need to follow few steps described below.
See image for the settings you need to do in the Build Settings.
Create a Custom Class of type UINavigationController say CustomNavController, then in the .m class add the following code.
-(BOOL)shouldAutorotate{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskAll;
}
Present the video controller as Modal using the CustomNavController, like below
VideoViewController *controller=[[VideoViewController alloc] initWithNibName:#"VideoViewController" bundle:nil];
CustomNavController *nav=[[CustomNavController alloc] initWithRootViewController:controller];
[self presentViewController:nav animated:YES completion:nil];
nav.navigationBar.hidden=YES;
And it should work, the trick is to separate rotations.
Related
When presenting a modal with UIModalPresentationCustom, it ignores the orientation methods, and displays / rotates to whatever the presenting VC is configured to.
Example:
Presenting VC supports Landscape and Portrait.
Presented VC supports Portrait only (via preferredInterfaceOrientationForPresentation and supportedInterfaceOrientations.
When presenting it in landscape without UIModalPresentationCustom, it rotates the view back to portrait, then presents the VC accordingly. Unfortunately, because I need the presenting VC to stay visible below, I am forced to use UIModalPresentationCustom. And when that happens, the presenting VC is forced into landscape mode, creating a messed up UI and generating constraint issues. And even when presenting in portrait, it becomes allowed to rotate into landscape, ignoring that shouldAutorotate returns NO.
PS: I found a workaround on iOS 7 by adding this method to my App Delegate, but it doesn't fix it on iOS 8.
#implementation UIViewController (customModalFix)
- (BOOL)shouldAutorotate
{
if ([self.presentedViewController isKindOfClass:[IntroViewController class]]) {
return [self.presentedViewController shouldAutorotate];
}
return YES;
}
#end
EDIT: Implementing supportedInterfaceOrientations on the presenting VC doesn't help at all, since it is only called when the view is loaded, not when a VC is about to be presented over it. Still haven't found a solution to this problem.
Maybe I'm late. The point is, when using UIModalPresentationCustom, the presenting VC will not disappear, and the presented VC is not considered to be presented full-screen (even if it does take up the full screen). Thus, it's the presenting VC that is consulted for the supported interface orientations. So the solution can be like:
- (NSUInteger)supportedInterfaceOrientations
{
if (self.presentedViewController) {
return [self.presentedViewController supportedInterfaceOrientations];
}
return [super supportedInterfaceOrientations];
}
If you only use UIModalPresentationCustom to keep the presenting VC visible below, say you need a clear colored VC, my answer here may work for you too:
https://stackoverflow.com/a/29167837/46940801
I have a problem with an app I am working on that goes like this:
The app's window has a rootViewController which is set to a custom class (MenuViewController) of UIViewController. This view controller has a rootViewController property of it's own. Whenever set this happens (really short version of the code):
- (void)setRootViewController:(UIViewControlelr *)rootViewController
{
...
_rootViewController = rootViewController;
if (self.rootViewController) {
[self addChildViewController:rootViewController];
[self.view addSubview:rootViewController.view];
}
...
}
Now this MenuViewController can show a modal view controller on top of it's rootViewController.
I do that like this:
[self.rootViewController presentModalViewController:viewController animated:YES completition:nil];
Everything looks to be ok until here. Now on iPad whenever I call [self.presentingViewController dismissViewControllerAnimated:YES completion:nil] from my modal view controller the interface beneath it rotates to the same orientation (that is UIInterfaceOrientationLandscapeLeft) regardless of what the initial orientation was when the view controller was presented.
So to conclude, my view's hierarchy is this:
Window
|
- Menu View Controller
|
- Root View Controller
|
- Modal view controller
Does anyone know how I can fix this? It doesn't happen on the iPhone.
It sounds to me as though on the iPad your MenuViewController's rootViewController supports multiple interface orientations, whereas on the iPhone it does not. This is speculation, as you have not said anything about this.
If this is the case, and the rootViewController does indeed support multiple interface orientations, the fix would be to override - supportedInterfaceOrientations and return portrait, which seems to be what you are suggesting you would want.
I want to embed an augmented reality controller into a custom view controller and i make this into viewDidLoad method of custom Controller.
These lines makes the job for me:
_arViewController = [[ARViewController alloc] initWithDelegate:self];
_arViewController.showsCloseButton = false;
[_arViewController setRadarRange:60];
[_arViewController setOnlyShowItemsWithinRadarRange:YES];
[self addChildViewController:_arViewController];
[[self view] addSubview:[_arViewController view]];
[_arViewController didMoveToParentViewController:self];
All work fine when i get into controller in Portrait mode and rotate the device.
Although when i get into controller in landscape mode and rotate the device in portrait the camera shows me only tha 1/2 of the view and the rest is blank.
If i replace the 3 last lines of the code above and push _arViewController to self.navigationController again all work fine for both orientations.
Can anyone help me with this issue? I prefer no to push the arController but have it into customViewController.
The project that i embedded into my App is the below:
iPhone -AR - Toolkit
First off all look at apple referce, it has some properties that might help you in block rotation: https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
In my point of view something like this may help you, just add method in .m file and implement correctly
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[_arViewController.view setFrame:self.view.frame];
}
On iOS6 I had a method to make one view controller in my navigation-style app auto rotate to landscape when I pushed it. (Basically present a bogus view controller and dismiss it in viewWillAppear).
UIViewController *mVC = [[UIViewController alloc] init];
[self presentModalViewController:mVC animated:NO];
if (![mVC isBeingDismissed])
[self dismissModalViewControllerAnimated:NO];
With the latest SDK this no longer works. Does anyone have another way to auto rotate?
Turns out the solution is simple, just pass YES to dismissModalViewControllerAnimated
UIViewController *mVC = [[UIViewController alloc] init];
[self presentModalViewController:mVC animated:NO];
if (![mVC isBeingDismissed])
[self dismissModalViewControllerAnimated:YES]; //Fix here
From Developer site
"When a view controller is presented over the root view controller, the system behavior changes in two ways. First, the presented view controller is used instead of the root view controller when determining whether an orientation is supported. Second, the presented view controller can also provide a preferred orientation. If the view controller is presented full screen, the user interface is presented in the preferred orientation. The user is expected to see that the orientation is different from the device orientation and rotate the device. A preferred orientation is most often used when the content must be presented in the new orientation."
I think here you can use the preferred orientation method here.
When the application is in landscape mode (which I plan to force), displaying a modal view causes the parent view to rotate to portrait mode. If I set the return value of shouldAutoRotateToInterfaceOrientation to NO, the parent does not rotate, however the modal then slides in from the side and displays sideways. Below is the code that reveals the modal.
- (IBAction)loadExistingGame:(id)sender {
SavedGamesTableViewController *savedGames = [[SavedGamesTableViewController alloc] initWithStyle:UITableViewStyleGrouped];
savedGames.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:savedGames animated:YES];
[savedGames release];
}
As per request here is the contents of the shouldAutoRotate method of the SavedGamesTableViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Override to allow orientations other than the default portrait orientation.
return YES;
}
Ok I figured out what needed to be done to fix it. The plist file that contains a list of the possible orientations needs to be limited to a single landscape view. The parent to the modal table view needs to have the shouldAutoRotateToInterfaceOrientation method return YES only if the orientation matches the only orientation in the plist file.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
return interfaceOrientation = UIInterfaceOrientationLandscapeRight;
}
the modal viewcontroller should return NO for the same method.
Based on
When the application is in landscape
mode (which I plan to force),
displaying a modal view causes the
parent view to rotate to portrait
mode.
and
As per request here is the contents of
the shouldAutoRotate method of the
SavedGamesTableViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Override to allow orientations other than the default portrait orientation.
return YES;
}
So what you're saying is that the parent view controller is not yet set to force only using landscape orientation, and when you show a modal view that is set to allow all orientations, you're wondering why your parent view rotates to portrait when you rotate the device to portrait? I don't understand your question... aren't you saying that parent view controller is currently set to allow rotation to portrait? Isn't this behaviour exactly what should happen?
I had a similar problem when bringing up a modal mail view. Forcing the rotation didn't work for me, but calling presentModalViewController on the application's main view controller rather than a child view controller solved the issue.
I was seeing the same behavior; in my case the problem was I had implemented shouldAutorotateToInterfaceOrientation to return YES unconditionally for the parent view controller but NOT for the presented modal view controller. So I suspect Shaggy Frog's comment is the key: whether you want to force landscape mode or not, you need to make sure that the two view controllers' shouldAutorotateToInterfaceOrientation implementations agree or weirdness will ensue.
UIViewController *vc = /* create view controller */;
UINavigationController *nc = nil;
if (IOS_VERSION_LESS_THAN_6_0) {
nc = [[MyCustomNavigationControllerSupportingAllOrientations alloc] initWithRootViewController:vc];
} else {
nc = [[UINavigationController alloc] initWithRootViewController:vc];
}
[self.navigationController presentModalViewController:nc animated:YES];
On iOS6 I use a UINavigationController.
On pre-iOS6 I subclass UINavigationController, like this:
#interface MyCustomNavigationControllerSupportingAllOrientations : UINavigationController
#end
#implementation MyCustomNavigationControllerSupportingAllOrientations
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
#end