I'm developing a new app in xcode and the app is in portrait view, but the video should be able to be in portrait and landscape view. I programmed this code but it doesn't work 100%
AppDelegate.h
#import <MediaPlayer/MediaPlayer.h>
#property (strong, nonatomic) MPMoviePlayerViewController *VideoPlayer;
AppDelegate.m
#synthesize VideoPlayer;
- (NSUInteger)application:(UIApplication *)application
supportedInterfaceOrientationsForWindow:(UIWindow *)window {
if ([[self.window.rootViewController presentedViewController]
isKindOfClass:[MPMoviePlayerViewController class]]) {
return UIInterfaceOrientationMaskAllButUpsideDown;
} else {
if ([[self.window.rootViewController presentedViewController]
isKindOfClass:[UINavigationController class]]) {
// look for it inside UINavigationController
UINavigationController *nc = (UINavigationController *)[self.window.rootViewController presentedViewController];
// is at the top?
if ([nc.topViewController isKindOfClass:[MPMoviePlayerViewController class]]) {
return UIInterfaceOrientationMaskAllButUpsideDown;
// or it's presented from the top?
} else if ([[nc.topViewController presentedViewController]
isKindOfClass:[MPMoviePlayerViewController class]]) {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
}
}
return UIInterfaceOrientationMaskPortrait;
}
The problem with this code is if user closes video player while it was watching video in landscape mode the whole app turns to landscape view even though I disabled it in Xcode GUI, after closing video player(app is in landscape view) if user rotate device to portrait it switches to portrait view and after that it stays in portrait (regardless device rotation). How can I make that app switches to portrait view even if user closes video player while he/she was watching video in landscape mode?
Thanks!
After long researches, I finally figured out the solution.
1) Enable All orientations for your application.
2) Subclass your root Navigation controller, and implement this 2 methods
- (BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
3) Subclass from MPMoviePlayerViewController
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
4) Now you should present subclassed MoviePlayerController, and all the stuff should work!
You almost got it right by adding the function in AppDelegate. The only problem is when user back from landscape video, the app become video. The solution is just here:
UIViewController *vc = [[self.window.rootViewController presentedViewController];
if ([vc isKindOfClass:[MPMoviePlayerViewController class]] &&
![vc isBeingDismissed]) {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
The key here is to double check if the presented view controller is being dismiss (exiting).
Related
In my app, all view controllers are having Portrait orientation except one. So let's name it, "GameViewController". The GameViewController is sticked to Landscape orientation only.
This is how I'm showing it in landscape mode:
MyViewController.m:
It's always in Portrait orientation, and from where we'll be presenting GameViewController.
- (void) showGameView {
GameViewController *gameView = (GameViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"GameViewController"];
[self presentViewController:gameView animated:YES completion:nil];
}
AppDelegate.m
This is how we're maintaining Landscape orientation forGameViewController.
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
if ([self.window.rootViewController.presentedViewController isKindOfClass: [GameViewController class]]) {
GameViewController *gameView = (GameViewController *) self.window.rootViewController.presentedViewController;
if (gameView.isPresented) {
return UIInterfaceOrientationMaskLandscape;
} else {
return UIInterfaceOrientationMaskPortrait;
}
}
else return UIInterfaceOrientationMaskPortrait;
}
We've requirement to dismiss GameViewController when app goes to background.
- (void)applicationDidEnterBackground:(UIApplication *)application {
if(self.window.rootViewController.presentedViewController) {
UIViewController *presentedVC = self.window.rootViewController.presentedViewController;
if([presentedVC isKindOfClass:[GameViewController class]]) {
GameViewController *gameView = (GameViewController *)self.window.rootViewController.presentedViewController;
gameView.isPresented = NO;
[gameView.presentingViewController dismissViewControllerAnimated:NO completion:nil];
}
}
}
GameViewController.m
We're setting these to make it available in AppDelegate.
- (void) awakeFromNib {
self.isPresented = YES;
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.isPresented = YES;
}
- (void) dismissView {
self.isPresented = NO;
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
Working as per expectation in following cases:
Open App
Open MyViewController
Call showGameView method
You will have a landscape orientation for GameViewController
Doesn't matters even if you would change phone to any orientation
Dismiss from GameViewController
Will come back to Portrait orientation for MyViewController
Everything looks good
Not working as per expectation in following cases:
Open App
Open MyViewController
Call showGameView method
Lock Phone
Change phone orientation to Landscape
Unlock phone, come back to the App
You will have a landscape orientation for MyViewController
Dismiss from GameViewController
Everything looks messed
This is app settings to handle different orientations:
I am trying to programmatically create UI orientation (portrait and landscape) using Objective C for all devices. Here the problem is I have multiple view controllers. I want to use multiple orientation into particular view controller.
For Ex:
Splash screen (App delegate - Portrait)
Login screen (Portrait)
Home screen (Both)
If I controlled by below method into App delegate root class then I cant enable both orientation into home view controller. Its showing black screen.
- (NSUInteger) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return UIInterfaceOrientationMaskPortrait;
}
You can try by following implementation. What here doing is, we sends the interfaceorientation we need for the visible view controller from app delegate. For that fist finds the visible viewcontroler and gets its supported interface orientation, If supportedInterfaceOrientations method not implemented in the visible view controller, return default orientation.
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
UIViewController *topController = [self topmostViewController];
if ([topController respondsToSelector:#selector(supportedInterfaceOrientations)]) {
return [topController supportedInterfaceOrientations];
}
return UIInterfaceOrientationMaskAllButUpsideDown;
}
- (UIViewController *)topmostViewController {
UIViewController *topController = self.window.rootViewController;
return [self topViewControllerWithRootViewController:topController];
}
- (UIViewController *)topViewControllerWithRootViewController:(UIViewController *)rootViewController {
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.topViewController];// dont use visible view controller, since it will return the presented ViewController, it may be UIAlertController.
} else if (rootViewController.presentedViewController && ![rootViewController.presentedViewController isKindOfClass:[UIAlertController class]]) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
And if you want to display any view controller with orientation other than UIInterfaceOrientationMaskAllButUpsideDown implement following method in your view controller
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return <whichever orientation you need>;
}
UPDATE:
Make sure that you selected only the orientations you needed for initial view controller in target settings.
Ref: Finding topmost view controller code from this answer with slight modification by addressing UIAlertcontroller presented case
I have a universal application that supports both iPad and iPhone. On the iPad I support all orientations and on the iPhone, only Portrait.
I want one view controller (which is displayed modally), when running on the iPhone, to be displayed in any orientation that the device is in. I have seen many tutorials and SO posts that suggest using the -(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window app delegate method and this seems to work absolutely fine in respect to rotating the modal view controller. However, when I dismiss the modal view whilst in landscape, the entire app remains landscape.
Ideally, as soon as the modal view is dismissed the app should go back into portrait mode.
After investigation, it appears that the -(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window callback is not called after dismissing the view controller and I can't figure out why.
I have had a play with the example app here, and the callback is fired when dismissing the view controller, which I can't figure out as to why. The only difference I can see is that my view hierarchy is a lot more complex and that I'm displaying a Navigation Controller rather than an explicit view controller but I don't see how that should affect the callback.
Any ideas as to finding a solution to this?
Thanks
You can try to use this method (working in app store build):
[[UIDevice currentDevice] performSelector:#selector(setOrientation:)
withObject:(__bridge id)((void*)UIInterfaceOrientationPortrait)];
In appdelegate:
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
// Get topmost/visible view controller
UIViewController *currentViewController = [self topViewController];
//Hire check your needed device ore other things you need
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone )
{
//device is iphone
if ([currentViewController respondsToSelector:#selector(canRotate)])
{
// Unlock landscape view orientations for this view controller
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}
else
//device Ipad
return UIInterfaceOrientationMaskAll;
}
}
- (UIViewController*)topViewController {
return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
} else if (rootViewController.presentedViewController) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
in the needed view to rotate make sure to implement
- (void)canRotate { }
This will allow you to rotate only the view you want for iPhone device.
I got this code with the help of an old stackoverflow post but i can`t find the link to it now
My application is working fine for iOS5. But for iOS6 I am getting the following orientation problem.
I have a ViewController VC1. when you rotate (change the orientation to UIInterfaceOrientationLandscapeRight) I want to present another ViewController VC2 and when you rotate back I need to dismiss VC2 and the VC1 should be in Portrait mode.
I am using tabBar in my application and I want this feature only for the first tab.
In tabBar I have written
-(BOOL) shouldAutorotate
{
UINavigationController *nav = (UINavigationController *)self.selectedViewController;
if ([nav.topViewController isKindOfClass:[MainViewController class]])
{
return YES;
}
else
{
return NO;
}
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
//Here I am writing code for presenting view(using notifications)
// but When I rotate the device to landscape it's getting called but when I rotate back
//to portrait I not getting called.
}
Thank you.
Please try this with ios 6 :(Example)
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationPortrait | UIInterfaceOrientationLandscapeRight | UIInterfaceOrientationLandscapeLeft;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
I know that there are lots of threads about how to force an orientation in IOS6 but none of them seems to work for me so now I need some help figuring this out.
I have a navigation based app that has many view controllers. All of them are in portrait view exept one that has to load in landscape mode (without having the user turning the phone first).
In the implementation of my navigation controller, I have added shouldAutorotate, supportedInterfaceOrientations and preferredInterfaceOriantationForPresentation.
#implementation UINavigationController (Rotation_IOS6)
- (BOOL)shouldAutorotate
{
return [self.topViewController shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [self.topViewController preferredInterfaceOrientationForPresentation];
}
#end
So it returns the values that have then defined in each view controller.
In the app delegate I have the supportedInterfaceOrientationsForWindow.
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
//Default orientations value
NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;
//Get orientation from the last view controller
if(self.window.rootViewController){
UIViewController *presentedViewController = [[(UINavigationController *)self.window.rootViewController viewControllers] lastObject];
orientations = [presentedViewController supportedInterfaceOrientations];
}
return orientations;
}
In each view controller I then have my settings for that view, for example:
// Only allow portrait view
-(NSInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
- (BOOL)shouldAutorotate {
return YES;
}
And I push the next view controller like this:
NextViewController *nxtController = [[NextViewController alloc] initWithNibName:#"NextViewController" bundle:nil];
[self.navigationController pushViewController:nxtController animated:YES];
But when I push the landscape view controller, while holding the phone in portrait orientation, It also loads in portrait mode. If I then tilt the phone it triggers the autorotate function and rotates the view into landscape mode, and then it is locked in that mode. However I need to lock it in landscape mode without using the phones orientation to trigger it to check autorotate.
Any ideas?
You could try to force the viewController to show in landscape by using the shouldaAutorotateToInterfaceOrientation that always return landscape, such as:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return ((interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (interfaceOrientation == UIInterfaceOrientationLandscapeRight));
}
go to project settings and remove the selection on the modes you do not want.