UIViewController do not rotate to landscape - ios

In many situation need to rotate the controller and is not working.
Right now I have the inverse of the problem: it is rotating, and I want to disable.
In that ViewController I have this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
}
but it is auto-rotating, because not this UIViewController is asked, but his parent in UI tree. Maybe that is the problem. The root controller must return Yes for all cases, because there are a few other UIViewControllers on the stack, which has / must have Portait / Landscape support.
I can't / don't want to touch other parts, because ... there are several reasons, for eg: the app is huge, with lot of know bugs and I don't want to make 1 and test it for 1 week, other is the deadline.
Please don't suggest it shouldn't be like this and must rewritten. I know.
How to deal with this controller to force Portait ?
Please read the bolded text too: can't force the whole app to support only Portait for 1 view controller, there are many on stack!

Try marking the app's supported Interface orientations in the properties file to only being portrait. But then of course in that function you just return YES on view controllers that you want to allow rotation. But then when you push it back in the stack the other views should be portrait.

detect the Landscape rotation and rotate to Portait:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
UIInterfaceOrientation appOrientation = [UIApplication sharedApplication].statusBarOrientation;
float width = self.view.bounds.size.width;
float height = self.view.bounds.size.height;
//NSLog(#"width %3.0f, height: %3.0f", width, height);
if((fromInterfaceOrientation == UIInterfaceOrientationPortrait || fromInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)){
// if is rotated from Portait:
if((appOrientation == UIInterfaceOrientationLandscapeLeft || appOrientation == UIInterfaceOrientationLandscapeRight)){
// to Landscape:
CGAffineTransform transform = self.view.transform;
transform = CGAffineTransformRotate(transform, -(M_PI / 2.0));
self.view.transform = transform;
[self.view setBounds:CGRectMake(0, 0, height, width)];
}
}
else {
// it is rotated from Landscape:
if((appOrientation == UIInterfaceOrientationPortrait || appOrientation == UIInterfaceOrientationPortraitUpsideDown)){
// to Portrait:
CGAffineTransform transform = self.view.transform;
transform = CGAffineTransformRotate(transform, +(M_PI / 2.0));
self.view.transform = transform;
[self.view setBounds:CGRectMake(0, 0, height, width)];
}
}
}
it isn't the best programming paradigm, but it does the trick.
Somebody write similar like tis to accept his answer, or write a better method, if you can!

Related

Second Screen display rotated 90 degrees in iOS 8.3 & 8.4

My question is less of how to fix the issue and more of why is this happening:
Starting in iOS 8.3, when displaying videos on a second screen (through either AirPlay or Lightning -> HDMI) the screen is rotated by 90ยบ. This isn't a problem on previous versions of iOS or when the app is launched in portrait instead of landscape.
I've created a workaround by checking for iOS version and screen rotation and then rotating the view for the second window. In case anyone else has this problem, here's my solution:
if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.3f) {
CGFloat width = (_externalWindow.frame.size.width > _externalWindow.frame.size.height) ? _externalWindow.frame.size.width : _externalWindow.frame.size.height;
CGFloat height = (_externalWindow.frame.size.width < _externalWindow.frame.size.height) ? _externalWindow.frame.size.width : _externalWindow.frame.size.height;
CGRect rotatedFrame = CGRectMake(0.0f, 0.0f, width, height);
_externalWindow.frame = rotatedFrame;
if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft && [[UIDevice currentDevice].systemVersion floatValue] < 9.0f) {
CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_2 * 3);
_externalWindow.transform = transform;
} else if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight && [[UIDevice currentDevice].systemVersion floatValue] < 9.0f) {
CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_2);
_externalWindow.transform = transform;
}
}
Edit: tested this on iOS 9 and found an interesting problem that's similar to the previous problem. The orientation was displaying correctly but the frame was still rotated so only part of the content was showing. I adjusted my solution to make sure the window frame is always oriented as widescreen.
Just so you know, I was able to solve this by only allowing portrait on the VC:
-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}

iOS Detect Today Extension Orientation

I'm trying to detect a Today Extension's orientation, but none of the typical methods seem to work.
I've tried the following:
[[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft;
[UIDevice currentDevice]orientation] = UIDeviceOrientationLandscapeLeft;
I've even tried using CMMotionManger.
Thanks for your help.
Seems like there is no bullet-proof solution for Extensions.
Look at this answer for possible workaround - https://stackoverflow.com/a/26023538/2797141
The orientation can't be detected by any normal means. However, every time the widget opens it calls "viewDidLoad". So, in viewDidLoad, detect screen width & height thusly and determine your own orientation.
int startOrientation;
int screenWidth = self.view.frame.size.width; //Screen Width
int screenHeight = self.view.frame.size.height; // Screen Height;
if (screenWidth > screenHeight) {
startOrientation = #"landscape";
} else {
startOrientation = #"portrait";
}

How to not to rotate a certain UIView allowing UIViewController's rotation

Does anyone know fix(not to rotate) a certain UIView with allowing rotation of UIViewController?
I want to implement a interface like camera app UI. A view showing camera's view does not rotate but HUD(like buttons) does rotate.
You can apply transformation to the view you don't want to rotate.
Use following method to do it.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(interfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
view.transform = CGAffineTransformMakeRotation(-M_PI/2);
}
else if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
{
view.transform = CGAffineTransformMakeRotation(M_PI/2);
}
return YES;
}

Augmented Reality App in Landscape Mode

I am trying to build an augmented reality app using the CoreMotion framework. I have tried to go off of Apple's pARk sample code project, but it only works in portrait mode. I need it to work in landscape. When switched to landscape mode the subviews in the overlay view move in the opposite directions and at the wrong rate (they either move too fast or too slow across screen)
I have read other postings that provide two solutions:
Create a reference attitude and apply the inverse of that attitude to the current attitude, as suggested in the CoreMotion Tea Pot Example.
Rotate the quaternion representation of the attitude 90 degrees
I do not think that the first will work because my augmented reality app requires that it be referenced to true north.
I also do not understand the math required to do the second.
Any suggestions on how to accomplish this complex problem I welcome.
How far are you now in your augmented reality app? I think beginning by taking a look at PARk from Apple is harsh. You need to have some advanced mathematical understanding. But if you do, why not!
you can take a look at this repository, this an augmented reality project working on Portrait and Landscape mode. Here is how the rotation is handled:
- (void)deviceOrientationDidChange:(NSNotification *)notification {
prevHeading = HEADING_NOT_SET;
[self currentDeviceOrientation];
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
// Later we may handle the Orientation of Faceup to show a Map. For now let's ignore it.
if (orientation != UIDeviceOrientationUnknown && orientation != UIDeviceOrientationFaceUp && orientation != UIDeviceOrientationFaceDown) {
CGAffineTransform transform = CGAffineTransformMakeRotation(degreesToRadian(0));
CGRect bounds = [[UIScreen mainScreen] bounds];
switch (orientation) {
case UIDeviceOrientationLandscapeLeft:
transform = CGAffineTransformMakeRotation(degreesToRadian(90));
bounds.size.width = [[UIScreen mainScreen] bounds].size.height;
bounds.size.height = [[UIScreen mainScreen] bounds].size.width;
break;
case UIDeviceOrientationLandscapeRight:
transform = CGAffineTransformMakeRotation(degreesToRadian(-90));
bounds.size.width = [[UIScreen mainScreen] bounds].size.height;
bounds.size.height = [[UIScreen mainScreen] bounds].size.width;
break;
case UIDeviceOrientationPortraitUpsideDown:
transform = CGAffineTransformMakeRotation(degreesToRadian(180));
break;
default:
break;
}
[displayView setTransform:CGAffineTransformIdentity];
[displayView setTransform: transform];
[displayView setBounds:bounds];
degreeRange = [self displayView].bounds.size.width / ADJUST_BY;
}
}
You have to rotate all your annotations and then your overlay view after the device rotation!
If you're really stuck, and are willing to use another toolkit, try iPhone-AR-Toolkit. It works in both portrait and landscape.

Forcing a layout position and size in iOS Superviews

I've got a massive problem and I really hope you can help me here... I'm very lost at the moment :(
I've got a project that runs with a MainWindow.xib. In my app delegate file I check the orientation of the device and load an appropriate NIB file that have different layouts (subviews) based on orientation. Here is the code to check the orientation:
-(void)checkTheOrientation
{
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight)
{
viewController = [[[MyViewController alloc] initWithNibName:#"MyWideViewController" bundle:nil] autorelease];
NSLog(#"Landscape = MyWideViewController");
}
else if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortraitUpsideDown)
{
viewController = [[[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil] autorelease];
NSLog(#"Portrait = MyViewController");
}
}
This works as expected and in Landscape or Portrait I am loading the correct views. The portrait view loads perfectly but the Landscape view loads with a thick black edge to the left as if it's x & y positions are not set to 0 & 0 respectively.
Here is the portrait view: http://uploads.socialcode.biz/2f25352B0e3x3z2t2z21
Here is the landscape view with the bug: http://uploads.socialcode.biz/1G2k3T012d1z0Y1U2q1k
In the MyViewController.m file I have a rough fix to get the sizing done correctly to avoid this big black strip on the left. Here's the code for this:
- (void) performLayout {
// Ensure the main view is properly placed
NSInteger MaxSizeHeight, MaxSizeWidth;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
MaxSizeHeight = 1024;
MaxSizeWidth = 768;
}
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight) {
CGRect mainViewFrame = [[self view] frame];
float width = mainViewFrame.size.width;
mainViewFrame.size.width = mainViewFrame.size.height;
mainViewFrame.size.height = width;
mainViewFrame.origin.x = 0;
mainViewFrame.origin.y = 0;
[[self view] setFrame:mainViewFrame];
} else {
CGRect mainViewFrame = [[self view] frame];
mainViewFrame.origin.x = MaxSizeWidth - mainViewFrame.size.width;
mainViewFrame.origin.y = MaxSizeHeight - mainViewFrame.size.height;
[[self view] setFrame:mainViewFrame];
}
// Ensure the content view is properly placed
CGRect contentFrame = [mainContentView frame];
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight)
{
contentFrame.size.width = MaxSizeHeight;
contentFrame.size.height = MaxSizeWidth;
}
contentFrame.origin.x = 0;
contentFrame.origin.y = 44;
[mainContentView setFrame:contentFrame];
// Ensure the content subviews are properly placed
contentFrame.origin.y = 0;
for (UIView *contentView in [mainContentView subviews]) {
[contentView setFrame:contentFrame];
}
}
The problem with this method is that this is just a very bad hack and it's not actually solving my problem. When it loads up in Landscape it now resizes and positions the subview to 1024x768,0,0 but any additional subviews that I load via other NIBs have the same problem.
What I would really like to know is how on earth can I set the landscape main superview to be 1024x768 position 0 & 0 without having to try and hack this together and keep performing the performLayout selector? At the moment there is a lot of inconsistence with this as the hack doesn't actually set the superview sizing correctly but rather just the subviews I load on top of the superview.
I thought that maybe a simple fix like this might solve the superview issue but alas it doesn't:
window.frame = CGRectMake(0, 0, 1024, 768);
I just want my main superview to be the placed and sized correctly at load and then the superviews just load in the right place. Please can you help me here???
First, UIView has a method named -layoutSubviews that you can override to position the subviews however you like. It'll be called when the view is first loaded, and again before drawing if you ever send it a -setNeedsLayout message.
Second, you should be able to properly set these positions in your .xib or storyboard file. Select your main view in its .xib file and check its position in the Size inspector. Also, ensure that the view is set to Landscape orientation in the Attributes inspector. If it's all correct, then there's something else going on. To simplify the problem, make a new project in Xcode with nothing but an empty view in landscape orientation. I just did one, and there's no position problem. That's what you want in your real app, so figure out what's happening in your real app to affect the view's position that's not happening in your new sample app.

Resources