iOS Detect Today Extension Orientation - ios

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";
}

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;
}

iPad2 only gives wrong width and height?

on any other device we use this code to set all views in landscape and everything fits great :
float width=[UIScreen mainScreen].bounds.size.width;
float height= [UIScreen mainScreen].bounds.size.height;
on the iPad 2 only , in order to make it work on landscape we have to swap the width and height, otherwise he puts views on portrait and they seems ugly.
Why is it happens only in iPad2 ?
It's not linked to the device but to iOS. Since iOS 8.0, the bounds is now dependent of the device orientation. I'm also swapping width and height like this :
CGRect ScreenBounds() {
CGRect bounds = [UIScreen mainScreen].bounds;
CGRect tmp_bounds = bounds;
if(bounds.size.width < bounds.size.height) {
bounds.size.width = tmp_bounds.size.height;
bounds.size.height = tmp_bounds.size.width;
}
return bounds;
}
Don't size your views relative to the screen, but relative to their container view. Simple as that.
I had same issue From iOS 8 UIScreen is interface oriented so you will get proper results on devices which are running on iOS 8.
In order to support iOS 7 as well you can use following util method:
+ (CGSize)screenSize {
CGSize screenSize = [UIScreen mainScreen].bounds.size;
if ((NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
return CGSizeMake(screenSize.height, screenSize.width);
}
return screenSize;
}

mainScreen bounds size differs on iOS 7 vs iOS 8 upon calling willRotateToInterfaceOrientation

I know iOS 8 now returns the proper screen dimensions for the current interface orientation. To get the device width for an orientation in iOS 7 you had to return the height if the orientation is landscape or width if the orientation is portrait, but you can always return the width in iOS 8. I have already taken that into consideration for an app I'm developing that will support iOS 7 and 8. (See code below)
However, I noticed another difference. If I call this method and pass in the orientation that it will be (obtained from willRotateToInterfaceOrientation), on iOS 7 it does return the proper width that it will be but on iOS 8 it returns the width for the old (current) orientation.
How can I get the width of the screen when I know the orientation it currently is or will be on iOS 8 and iOS 7?
While I could just swap the width and height for iOS 8, this would return an incorrect value when this function is called while the device isn't transitioning to a new orientation. I could create two different methods but I'm looking for a cleaner solution.
- (CGFloat)screenWidthForOrientation:(UIInterfaceOrientation)orientation
{
NSString *reqSysVer = #"8.0";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending) {
return [UIScreen mainScreen].bounds.size.width;
}
CGRect screenBounds = [UIScreen mainScreen].bounds;
CGFloat width = CGRectGetWidth(screenBounds);
CGFloat height = CGRectGetHeight(screenBounds);
if (UIInterfaceOrientationIsPortrait(orientation)) {
return width;
} else if (UIInterfaceOrientationIsLandscape(orientation)) {
return height;
}
return width;
}
Use cases:
iPad running iOS 7:
calling [self screenWidthForOrientation:[UIApplication sharedApplication].statusBarOrientation] in viewDidAppear returns the correct width
calling [self screenWidthForOrientation:toInterfaceOrientation] in willRotateToInterfaceOrientation:toInterfaceOrientation:duration returns the correct width
iPad running iOS 8:
calling [self screenWidthForOrientation:[UIApplication sharedApplication].statusBarOrientation] in viewDidAppear returns the correct width
calling [self screenWidthForOrientation:toInterfaceOrientation] in willRotateToInterfaceOrientation:toInterfaceOrientation:duration returns the incorrect width (what it currently is before the rotation occurs)
Here is my code to calculate correct width and height for iOS7 / iOS8 before applying constraints.
- (void) applyConstraints:(UIInterfaceOrientation)toInterfaceOrientation
{
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
CGFloat heightOfScreen;
CGFloat widthOfScreen;
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
// iOS 8.0 and later code here
if ([UIApplication sharedApplication].statusBarOrientation == toInterfaceOrientation) {
heightOfScreen = screenSize.height;
widthOfScreen = screenSize.width;
} else {
heightOfScreen = screenSize.width;
widthOfScreen = screenSize.height;
}
} else {
if (UIDeviceOrientationIsLandscape(toInterfaceOrientation)) {
heightOfScreen = screenSize.width;
widthOfScreen = screenSize.height;
} else {
heightOfScreen = screenSize.height;
widthOfScreen = screenSize.width;
}
}
//Applying new constraints
...
}
It is not so beautiful but it works =)
In iOS 8, the entire nature of rotation and the coordinate system is totally changed. You should not be using any events like willRotate; they are deprecated. The entire app rotates, including the screen. There are no more rotation transforms; the whole app (screen, window, root view) just gets wider and narrower, and that's how you know something has happened (or you can register to hear about the status bar changing its orientation). If you want to know the device coordinates, independent of rotation, that is what the new screen coordinate spaces are for (fixedCoordinateSpace is the one that doesn't rotate).

incorrect view size ios

I am using UIViewController for display my view. My view have been created in interface builder.
Right now these are next parameters for view:
width: 568
height: 320
Orientation: Landscape
in ViewController I have next code:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return ((interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (interfaceOrientation == UIInterfaceOrientationLandscapeRight));
}
in info.plist I have added just two interface orientation right and left.
but when I try to output width of my view in code I get 320 and when I try to output height it write down in console 568 but I expect 320 instead.
I don't know why it works like this. Any suggestions?
even if I add this:
[self.view setFrame:CGRectMake(0, 0, 568, 320)]; in viewDidLoad method. even then I have inccorect height
I need to know width size I use in this method:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
CGFloat width = 0.0f;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
width = 568.0f;
} else {
width = 1024.0f;
}
NSInteger page = scrollView.contentOffset.x / width;
NSLog(#"%d", page);
}
Right now I use hardcode variable of width, but how come. Why I can't use self.view.frame.size.width because the sides swop each other - because.
Maybe you're printing width and height in the viewDidLoad method before the orientation occurs. Try to print it on viewWillAppear or with performSelector:afterDelay:
Another thing that might affect the dimension of the view is how you set the autoresizing mask on the interface builder (the red arrows below the x,y,height,width section on the right panel)
Please add LaunchScreen.storyboard in your project and set it as your Launch Screen under
Targets > General > App Icons and Launch Images > Launch Screen file.

UIViewController do not rotate to landscape

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!

Resources