So, I've given up on trying to solve an issue I've been having where my controller will rotate without calling my shouldAutorotateToInterfaceOrientation: method, because everyone for a few years has been stating it as an iOS bug.
Now I need to just force rotate my UIViewController. Is there a way I can do that, since the UIDevice instance method has been removed now and I don't know what to do to force rotate my controller.
I'm not sure which UIDevice method that you are saying has been removed, but the following has worked for me (this does use the UIDevice orientation method). Bottom line, if you have a view that only accepts landscape, you can use the following to force iOS to change the orientation. It's curious, but it works. I apologize that I can't give credit to the original author, but once came across this elsewhere on StackOverflow:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
- (void)forceLandscape
{
// make sure shouldAutorotateToInterfaceOrientation is configured to accept only landscape
if (UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]))
{
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window addSubview:view];
}
}
The equivalent to force portrait mode (assuming, of course, your shouldAutorotateToInterfaceOrientation accepts only portrait):
- (void)forcePortrait
{
// make sure shouldAutorotateToInterfaceOrientation is configured to accept only portrait
if (UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]))
{
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window addSubview:view];
}
}
Using xcode7.3 ios9.
I have been trying to force landscape view on and off for over a week now, no hair left :(. For anyone else finding this question and none of the answers work, or any of the other myriad answers on forcing landscape, I finally found something that works here:
http://www.btday.com/how-to-force-view-controller-orientation-in-ios-8/
Suggestion is to put operation in viewDidAppear, but it also seems to work in viewWillAppear and is slightly less ugly.
override func viewWillAppear(animated: Bool) {
UIDevice.currentDevice().setValue(UIInterfaceOrientation.LandscapeLeft.rawValue, forKey: "orientation")
}
If this is wrong/bad, please speak up, only had a mac for a little over a month so I'm a total nuub!
Also note I'm using a UITabBarController and it doesn't seem to matter whether you put this in the tab bar controller or one of it's children
Related
I have an app with all screens in portrait except for one. In iOS 8 that one landscape page appears fine, until the device gets rotated in any direction. The view rotates on a weird axis and parts of it go off screen.
I've tried updating the frame of the view in viewWillTransitionToSize, but it just causes even more issues, changing the frames of subviews to be super crazy.
Some solutions have suggested doing this:
- (void)applicationDidChangeStatusBarOrientation:(NSNotification *)notification
{
[UIViewController attemptRotationToDeviceOrientation];
}
But that didn't work for me. Any ideas? Thanks!
The offending line will be in your AppDelegate didFinishLaunchingWithOptions function and looks like the following:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
Please try this.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
This will allowed for both left and right landscape (but it deprecated since iOS6).
Or this one but I'm not test it.
- (BOOL)shouldAutorotate {
return NO;
}
I have used the below code to force the view to landscape.
objc_msgSend([UIDevice currentDevice], #selector(setOrientation:), UIInterfaceOrientationLandscapeLeft);
Is apple approve this for orientation or have any chance to reject my app.Please provide your solution.
I do not think so. Apple documentation state that orientation is read-only property.
To force landscape into ViewController, you can do:
- (NSUInteger)supportedInterfaceOrientations;
{
return UIInterfaceOrientationMaskLandscape;
}
To present the ViewController in a specified orientation mode:
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation;
{
return UIInterfaceOrientationLandscapeLeft;
}
For all these to happen, the plist of the project must support the orientation and:
- (BOOL)shouldAutorotate;
{
return YES;
}
All these is assuming the view controller is not presented under same UINavigationController. For such case, you should refer to this discussion on work around of forcing rotation on UINavigationController: UINavigationController Force Rotate
For views that you want to force into landscape, you can always use transform:
self.view.transform = CGAffineTransformMakeRotation(M_PI/2.0);
I have a tabBarController with 2 elements: KeyPad, List
The KeyPad- needs to be set only to portrait mode. Inside the UINavigationController - I override the methods:
- (BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
List item starts from a RotationNavigationController - here i ve set all the rotations available.
Everything seems to work ok except of one thing:
when navigating from List item Bar Controller (which is in Landscape) to KeyPad item bar controller - KeyPad is also in landscape mode. It seems that the 2 methods (shouldAutorotate & supportedInterfaceOrientations) are not called. How to solve this?
I;ve also added the following in viewWillApppear (inside Keypad - which extend a UIViewController)
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft || [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight){
// Landscape - WHAT TO DO HERE?
NSLog(#"landscape");
}
EDIT:
*Here is what I did for my problem:*
//set statusbar to the desired rotation position
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft animated:NO];
//present/dismiss viewcontroller in order to activate rotating.
UIViewController *mVC = [[[UIViewController alloc] init] autorelease];
[self presentModalViewController:mVC animated:NO];
[self dismissModalViewControllerAnimated:NO];
When you move from one orientation tab to another, it's shouldAutorotate is called before anything else. Since you have specified NO. It stays at it's previous orientation. I worked around this by setStatusBarOrientation in the viewWillAppear:
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
But I will have to warn you, this changes some things, like if you are checking for orientation anywhere in your code, you will have to check the statusBarOrientation instead of the orientation of your view/viewController.
Okay, so here's the situation:
I have an app in which I only want ONE specific view in a UINavigationController to have a landscape orientation. This view is a UIImageView that I'm capturing a signature on (THAT part works awesome). So, like this:
previous view --> signature view --> next view
(portrait) (landscape) (portrait)
I can't seem to find a good way to force the device orientation to landscape on that signature screen. It'll never make sense to have a portrait orientation on the signature view because there's really not adequate room for signing in that screen width.
So, any bright ideas on how to accomplish this? I've considered possibly doing the signature view modally, thus breaking out of the navigation controller. Thoughts?
You can try to force Device to rotate to necessary orientation - but you need to handle it manually (in addition to overriding UIViewController orientation handling methods).
To rotate device you can use next methods:
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
But in it may not work in all situations...
Also available undocumented approach:
[[UIDevice currentDevice] performSelector:NSSelectorFromString(#"setOrientation:")
withObject:(__bridge id)((void*)UIInterfaceOrientationLandscapeLeft)];
Just override this UIViewController method to only return true for landscape like so and the iphone will be forced to rotate to that device orientation, since it has no other option.
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
Unfortunately, all root UIViewControllers inside of a Navigation Controller must support any of their child orientations. This means that the first view controller in your setup must support landscape, otherwise the child will only support portrait.
The best way to implement what you are looking for is to create a UIViewController that displays its content view on a rotated transform, and just default all UIViewControllers in that stack to portrait.
I think you can embed this view inside a view controller and overwrite the ShouldRotateToInterfaceOrientation method.
Good luck!
To use a View in only landscape, I have the following in the ViewController:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight || interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
This might be what your looking for.
// Rotates the view.
CGAffineTransform transform = CGAffineTransformMakeRotation(3.14159/2);
self.view.transform = transform;
// Repositions and resizes the view.
CGRect contentRect = CGRectMake(-80, 80, 480, 320);
self.view.bounds = contentRect;
from http://www.iphonedevsdk.com/forum/iphone-sdk-development/1394-landscape-uiviewcontroller-uiview-rotation.html
I have an app that has landscape only views that even starts in landscape. This was working fine in iOS 5.x but stopped working in iOS 6.x
After trying many many things, some more questionable than others, I found a solution that to me is clear and predictable.
I did several things.
-- I kept the views in landscape mode in IB.
-- I checked both landscape modes in the project settings - there a four icons there to control it
-- Orientation mgmt has changed in iOS 6.x. I had to overwrite a few methods to support changing to landscape
this method is for iOS 5.x
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations.
return (interfaceOrientation & UIInterfaceOrientationMaskLandscape);
}
these 2 methods are for iOS 6.x
- (NSUInteger)supportedInterfaceOrientations
{
NSUInteger supportedOrientations = UIInterfaceOrientationMaskLandscape;
return supportedOrientations;
}
- (BOOL)shouldAutorotate
{
return YES;
}
-- But the key was to change the logic in the AppDelegate. Original code I had there was adding a subview (controller.view) to the window. This stopped working in iOS 6.x - I changed the call to window.setRootController. That was the final step that sealed it - it would not work without making this final change
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//[self.window addSubview:viewController.view];
[self.window setRootViewController:viewController];
[self.window makeKeyAndVisible];
return YES;
}
The UINavigationController overrides the contain UIViewController orientation settings, so you have to create a custom subclass of UINavigationController with the following for 5.1:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[self topViewController] isKindOfClass:[SigCaptureViewController class]]) {
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
} else {
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}
}
For 6.0 and above you need:
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
if ([[self topViewController] isKindOfClass:[EXTRASigCaptureViewController class]]) {
return UIInterfaceOrientationMaskLandscape;
} else {
return UIInterfaceOrientationMaskPortrait;
}
}
What I haven't figured out is how to make the force the UINavigationController to rotate. calling [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO] causes the status bar to rotate but doesn't cause the view to rotate.
So I have a UISplitViewController that is the root view of my program. I have set the initial orientation to be LandscapeLeft and have all 4 orientations supported in my plist.
If I launch the app in portrait - the view that is shown is my root view not the detail view which obviously is not what I want. As soons as I rotate the device, everything works from there.
I have scoured this site and others but have found no fixes. The closest I have come is the adding the following to my app delegate:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
if (UIDeviceOrientationIsValidInterfaceOrientation([UIDevice currentDevice].orientation)) {
if (UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation))
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeLeft;
else
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationPortrait;
}
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
So this essentially forces it to draw correctly, which works great except for when the app launches with the device laying flat. Then I dont know the portrait vs landscape (and I know of no way to find it). So I basically then cant accurately say what to do.
The larger thing is this above code is a HACK, and there should be a better way, but for the life of me I cant find it.
Any ideas?
Thanks for your code on fixing this for portrait and landscape. I found a quick fix for the issue when its flat on the desk or upside down(not sure who would start the app upside down, but the same issue happens in this case):
if (UIDeviceOrientationIsValidInterfaceOrientation([UIDevice currentDevice].orientation)) {
if (UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation))
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeLeft;
else if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation))
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationPortrait;
}
else {
if (([UIApplication sharedApplication].statusBarOrientation == 1) || ([UIApplication sharedApplication].statusBarOrientation == 0))
{
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationPortrait;
}
else {
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeLeft;
}
NSLog(#"orientation: %d", [UIApplication sharedApplication].statusBarOrientation);
}
In my App, this works because I just wanted to force them into portrait to start and if they move to landscape after that, it rotates and works fine because I support all orientations.
I don't think this will work in all cases, but this might help you get on the right track. You just need to play with the statusBarOrientation value and manually set it based on what you find works if the InterfaceOrientation is not valid(which it isn't if the device is flat on a table or upside down).
Hope that helps...
Edit: Also, I have a need in my App for knowing orientation while they are picking new items in the SplitViewController, so it was being wonky when the device was flat or upside down. And the way I detected if it was flat or upside down was to first see if the orientation was valid like you did:
if (UIDeviceOrientationIsValidInterfaceOrientation([UIDevice currentDevice].orientation))
But then if its not, I check to see if self.popoverController is nil. If its not, then its in portrait and if it is, then its landscape (based on how the splitViewController works by setting that to nil or not):
if (self.popoverController)
{
NSLog(#"in portrait");
}
else {
NSLog(#"in landscape");
}
This wouldn't work in the App Delegate while the App is launching though because this detailViewController isn't being used at that point. Just thought I'd let you know if it helps out any.
Your RootViewController is showing in place of your detailViewCOntroller?
it seems you're doing something bad... (maybe inverted viewControllers order in SplitViewController.viewControllers ?)
You need to make sure to add your UISplitViewController's view to the UIWindow INSIDE the application:application didFinishLaunchingWithOptions: method of your app delegate (not later), or the split view won't rotate correctly initially.