How Do I detect the orientation of the device on iOS?
I have a question on how to detect the device orientation on iOS. I don't need to receive change notifications, just the current orientation itself. This seems to be a rather simple question, but I haven't been able to wrap my head around it. Below is what I have done so far:
UIDevice *myDevice = [UIDevice currentDevi开发者_StackOverflow社区ce] ;
[myDevice beginGeneratingDeviceOrientationNotifications];
UIDeviceOrientation deviceOrientation = myDevice.orientation;
BOOL isCurrentlyLandscapeView = UIDeviceOrientationIsLandscape(deviceOrientation);
[myDevice endGeneratingDeviceOrientationNotifications];
In my mind this should work. I enable the device to receive device orientation notices, then ask for what orientation it is in, but then it is not working and I don't know why.
Really old thread, but no real solution.
I Had the same problem, but found out that getting The UIDeviceOrientation isn't always consistent, so instead use this:
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if(orientation == 0) //Default orientation
//UI is in Default (Portrait) -- this is really a just a failsafe.
else if(orientation == UIInterfaceOrientationPortrait)
//Do something if the orientation is in Portrait
else if(orientation == UIInterfaceOrientationLandscapeLeft)
// Do something if Left
else if(orientation == UIInterfaceOrientationLandscapeRight)
//Do something if right
if UIViewController:
if (UIDeviceOrientationIsLandscape(self.interfaceOrientation))
{
//
}
if UIView:
if (UIDeviceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation))
{
//
}
UIDevice.h:
#define UIDeviceOrientationIsPortrait(orientation) ((orientation) == UIDeviceOrientationPortrait || (orientation) == UIDeviceOrientationPortraitUpsideDown)
#define UIDeviceOrientationIsLandscape(orientation) ((orientation) == UIDeviceOrientationLandscapeLeft || (orientation) == UIDeviceOrientationLandscapeRight)
Updated:
add this code to xxx-Prefix.pch then you can use it anywhere:
// check device orientation
#define dDeviceOrientation [[UIDevice currentDevice] orientation]
#define isPortrait UIDeviceOrientationIsPortrait(dDeviceOrientation)
#define isLandscape UIDeviceOrientationIsLandscape(dDeviceOrientation)
#define isFaceUp dDeviceOrientation == UIDeviceOrientationFaceUp ? YES : NO
#define isFaceDown dDeviceOrientation == UIDeviceOrientationFaceDown ? YES : NO
usage:
if (isLandscape) { NSLog(@"Landscape"); }
For what You looking for first you have to Get Notification if Orientation Changed! You Can set This Thing in viewDidLoad like
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(OrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
and whenever Orientation of your Device changed OrientationDidChange Called where You can do whatever You Want as Per Orientation
-(void)OrientationDidChange:(NSNotification*)notification
{
UIDeviceOrientation Orientation=[[UIDevice currentDevice]orientation];
if(Orientation==UIDeviceOrientationLandscapeLeft || Orientation==UIDeviceOrientationLandscapeRight)
{
}
else if(Orientation==UIDeviceOrientationPortrait)
{
}
}
If you want to get device orientation directly from accelerometer use [[UIDevice currentDevice] orientation]
. But if you need current orientation of your application(interface orientation) use [[UIApplication sharedApplication] statusBarOrientation]
.
UIViewController
has an interfaceOrientation
property that you can access to find out the current orientation of a view controller.
As for your example, that should work. When you say it isn't working, what do you mean? What results does it give you versus what you expected?
In Swift 3.0
to get device orientation.
/* return current device orientation.
This will return UIDeviceOrientationUnknown unless device orientation notifications are being generated.
*/
UIDevice.current.orientation
to get device orientation from your app
UIApplication.shared.statusBarOrientation
Wasn't satisfied by "UIDeviceOrientation" because when a UIViewcontroller orientation is fixed to a specific orientation you don't get a pertinent information with the device orientation, so the right thing to do is using "UIInterfaceOrientation".
You can get the orientation from the UIViewController with a "self.interfaceOrientation", but when you are factorizing our code, you might need to do this kind of test outside a view controller, (custom view, a category…), so you still can access the information anywhere outside the controller by using the rootviewController:
if (UIInterfaceOrientationIsLandscape(view.window.rootViewController.interfaceOrientation)) {
}
There's a way to achieve this whether the orientation lock is enabled or not by using data from CoreMotion. This is the code:
#import <CoreMotion/CoreMotion.h>
CMMotionManager *cm=[[CMMotionManager alloc] init];
cm.deviceMotionUpdateInterval=0.2f;
[cm startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue]
withHandler:^(CMDeviceMotion *data, NSError *error) {
if(fabs(data.gravity.x)>fabs(data.gravity.y)){
NSLog(@"LANSCAPE");
if(data.gravity.x>=0){
NSLog(@"LEFT");
}
else{
NSLog(@"RIGHT");
}
}
else{
NSLog(@"PORTRAIT");
if(data.gravity.y>=0){
NSLog(@"DOWN");
}
else{
NSLog(@"UP");
}
}
}];
Have you unlocked the hardware lock for device orientation? There is one at the edge of my iPad 1.
Here is some Swift variables to make detection easier:
let LANDSCAPE_RIGHT: Bool = UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeRight
let LANDSCAPE_LEFT: Bool = UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeLeft
let LANDSCAPE: Bool = LANDSCAPE_LEFT || LANDSCAPE_RIGHT
let PORTRAIT_NORMAL: Bool = UIDevice.currentDevice().orientation == UIDeviceOrientation.Portrait
let PORTRAIT_REVERSE: Bool = UIDevice.currentDevice().orientation == UIDeviceOrientation.PortraitUpsideDown
let PORTRAIT: Bool = PORTRAIT_REVERSE || PORTRAIT_NORMAL
My current way of doing this:
+ (BOOL)isPortrait {
let window = UIApplication.sharedApplication.delegate.window;
if(window.rootViewController) {
let orientation =
window.rootViewController.interfaceOrientation;
return UIInterfaceOrientationIsPortrait(orientation);
} else {
let orientation =
UIApplication.sharedApplication.statusBarOrientation;
return UIInterfaceOrientationIsPortrait(orientation);
}
}
If there is for some reason no rootViewController yet fail safe to statusBarOrientation...
And the best reliable way in swift :
public extension UIScreen {
public class var isPortrait: Bool {
UIApplication.shared.delegate?.window??.rootViewController?.interfaceOrientation.isPortrait ??
UIApplication.shared.statusBarOrientation.isPortrait
}
public class var isLandscape: Bool { !isPortrait }
}
This is my solution with Combine, which is quite easy to use with SwiftUI or regular Swift Object. A singleton object (static instance) is better than the "environment" for this kind of truly global object.
// Singleton object to keep the interface orientation (and any other global state)
class SceneContext: ObservableObject {
@Published var interfaceOrientation = UIInterfaceOrientation.portrait
static let shared = SceneContext()
}
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
...
func windowScene(_ windowScene: UIWindowScene, didUpdate previousCoordinateSpace: UICoordinateSpace, interfaceOrientation previousInterfaceOrientation: UIInterfaceOrientation, traitCollection previousTraitCollection: UITraitCollection) {
SceneContext.shared.interfaceOrientation = windowScene.interfaceOrientation
}
}
// if you want to execute some code whenever the orientation changes in SwiftUI
someView {
....
}
.onReceive(SceneContext.shared.$interfaceOrientation) { (orientation) in
// do something with the new orientation
}
// if you want to execute some code whenever the orientation changes in a regular Swift object
let pub = SceneContext.shared.$interfaceOrientation.sink(receiveValue: { (orientation) in
// do something with the new orientation
...
})
精彩评论