Related
I need to get device orientation from a ViewController. I cannot base on:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
because it sometimes returns orientation unknown (for example when the device lays on the table).
I just need to know in what orientation is my current UIView displayed (is it landscape left or landscape right). I don't need to have this value updated when orientation changes, I just want to know it, when I ask for it. Just some reference view.orientation ;). Is there something that would help me? I've read UIView documentation, found some reference to UIWindow, but nothing that could help me.
You can also get the device orientation from UIApplication, have you tried using
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
UIViewController has a property
UIInterfaceOrientation interfaceOrientation;
So in your UIViewController, you can access the current orientation of the device at any time via
UIInterfaceOrientation myCurrentOrientation = self.interfaceOrientation;
Swift Version
let currentOrientation:UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation
if currentOrientation.isPortrait {
print("PORTRAIT")
} else if currentOrientation.isLandscape {
print("LANDSCAPE")
}
Following is the sample code to do the same. There is a variable named deviceOrientation, and it will answer the current orientation of device, whenever being asked.
UIDeviceOrientation deviceOrientation;
- (void)viewWillAppear:(BOOL)animated
{
deviceOrientation = (UIDeviceOrientation)[[UIApplication sharedApplication] statusBarOrientation];
[self willAnimateRotationToInterfaceOrientation:deviceOrientation duration:0.5];
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
deviceOrientation = (UIDeviceOrientation)interfaceOrientation;
if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
NSLog(#"Landscape");
}
else
{
NSLog(#"Portrait");
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return TRUE;
}
Is anyone know a way to detect the orientation of the iPad programmatically when launch a app.
I'm using following mechanism.
- (void) detectDeviceInitialOrientation
{
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
MyAppDelegate *appDelegate=(MyAppDelegate*)[[UIApplication sharedApplication] delegate];
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (UIDeviceOrientationIsPortrait(orientation)) {
appDelegate.orintation = PORTRAIT;
}
else if (UIDeviceOrientationIsLandscape(orientation)) {
appDelegate.orintation = LANDSCAPE;
}
}
But it fails to detect the device's orientation when it lay parallel to the floor. So, I'm looking another solution. Please help......
Have a look at the UIDeviceOrientation enum in the docs.
typedef enum {
UIDeviceOrientationUnknown,
UIDeviceOrientationPortrait,
UIDeviceOrientationPortraitUpsideDown,
UIDeviceOrientationLandscapeLeft,
UIDeviceOrientationLandscapeRight,
UIDeviceOrientationFaceUp,
UIDeviceOrientationFaceDown
} UIDeviceOrientation;
Notice that this defines UIDeviceOrientationFaceUp and UIDeviceOrientationFaceDown. Unfortunately, there is no built in check for whether the device is in one of these orientations like there is for portrait or landscape. However, you can do the checking your self with a simple if statement. Something like this:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationFaceUp || orientation == UIDeviceOrientationFaceDown) {
// device is flat on the ground
}
I have the following code to fill a view according to the orientation. This always returns landscape.
- (void)setData:(BCPlaylist *)list {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationPortrait || orientation == UIDeviceOrientationPortraitUpsideDown){
NSLog(#"portrait");
[self setPlaylist:list];
[self renderPlaylist];
[activity stopAnimating];
}else{
NSLog(#"landscape");
[self setPlaylist:list];
[self renderPlaylistOne];
[activity stopAnimating];
}
}
I change views correctly in - (void)animateRotation:(UIInterfaceOrientation)interfaceOrientation
duration:(NSTimeInterval)duration {
But that doesn't work when already in landscape or portrait when changing a playlist.
Instead of using [[UIDevice currentDevice] orientation] for checking orientation use statusbar orientation to get the exact orientation.
UIDeviceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
To avoid a warning, use :
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
You'd always get landscape, because that's your default (from your if statement). If you walk through the debugger with a breakpoint there, you'll see that the orientation reported is that of Unknown.
In fact, your code is fine, but this is a limitation of the simulator. If you take the same code, using Device orientation and not Interface orientation, you'll get actual values if you use it on the physical device, which can be driven by the if-statement you have.
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 currentDevice] ;
[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
...
})
I have an app with a tab bar, and nav controllers in each tab. When user shakes the device, a UIImageView appears as a child view in the nav controller. But the UIImageView must contain a special image, depending on the device's current orientation.
If I write just
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)
if (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
//Code
}
else if (interfaceOrientation == UIInterfaceOrientationLandscapeRight||interfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
//Code
}
}
The view just goes crazy if user rotated the device before shaking.
Is there a method to get iPhones current orientation?
Here are macros UIDeviceOrientationIsLandscape and UIDeviceOrientationIsPortrait
so rather checking separately you can do it like this ...
if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation))
{
// code for landscape orientation
}
OR
if (UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation))
{
// code for Portrait orientation
}
Use the [[UIDevice currentDevice] orientation] method, as specified here.
As beno said, this seems a better answer if you are detecting orientation early in your View. I couldn't get the approved answer to return a result early in my setup but this works wonderfully.
if (UIDeviceOrientationIsPortrait(self.interfaceOrientation)){
//DO Portrait
}else{
//DO Landscape
}
To addon to the already answered question:
You use [[UIDevice currentDevice] orientation] which will yield one of these values:
typedef enum {
UIDeviceOrientationUnknown,
UIDeviceOrientationPortrait,
UIDeviceOrientationPortraitUpsideDown,
UIDeviceOrientationLandscapeLeft,
UIDeviceOrientationLandscapeRight,
UIDeviceOrientationFaceUp,
UIDeviceOrientationFaceDown
} UIDeviceOrientation;
The documentation can be found here - (orientation) and here - (UIDeviceOrientation).
(I don't mean to claim the former anwser, but this information was to big for a comment.)
Try this:
[[UIApplication sharedApplication] statusBarOrientation]
Or in Swift 3:
UIApplication.shared.statusBarOrientation
To specifically check for a particular orientation you can also try the isLandscape or isPortrait property like so:
UIApplication.shared.statusBarOrientation.isLandscape
The problem with [[UIDevice currentDevice] orientation] is that it will also return UIInterfaceOrientationUnknown which statusBarOrientation does not.
There is also a UIViewController property interfaceOrientation but it was deprecated in iOS 8, so it's not recommended.
You check documentation for statusBarOrientation here
You can also use the interfaceOrientation property of the UIViewController class, if you are stuck and continuously getting UIDeviceOrientationUnknown from UIDevice.
There's a good summary of why [[UIDevice currentdevice] orientation] can sometimes fail here: http://bynomial.com/blog/?p=25, especially if you want to detect the orientation quickly (for example, if you wanted to check right when the app comes out of the background).
It helps you...
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft || [[UIDevice currentDevice] orientation ]== UIDeviceOrientationLandscapeRight)
{
NSLog(#"Lanscapse");
}
if([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown )
{
NSLog(#"UIDeviceOrientationPortrait");
}
}
As Simple Solution of Swift 4.2
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
switch UIDevice.current.orientation{
case .portrait:
print("Portrait")
case .portraitUpsideDown:
print("PortraitUpsideDown")
case .landscapeLeft:
print("LandscapeLeft")
case .landscapeRight:
print("LandscapeRight")
default:
print("Another")
}
}
You can also define constants to earn time :
#define LANDSCAPE UIInterfaceOrientationIsLandscape(self.interfaceOrientation)
#define LANDSCAPE_RIGHT [UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft
#define LANDSCAPE_LEFT [UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight
#define PORTRAIT UIInterfaceOrientationIsPortrait(self.interfaceOrientation)
#define PORTRAIT_REVERSE [UIDevice currentDevice].orientation == UIDeviceOrientationPortraitUpsideDown
Updating this to iOS 8+ where the UIViewController.interfaceOrienation is deprecated, you should use traitCollections. So for example, to check for landscape on iPhone, you'd use:
if self.traitCollection.verticalSizeClass == .compact
{
your code
}
Notice that this is not the case on iPad, because on iPad in landscape, the size class is not compact.
Apple Doc Link
And if you simply want whether the device is in landscape or portrait, a simple solution is (in Swift):
var orientation = "portrait"
if UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height {
orientation = "landscape"
}
You could check it like so (Swift 3):
var isPortrait: Bool {
let orientation = UIDevice.current.orientation
switch orientation {
case .portrait, .portraitUpsideDown:
return true
case .faceUp, .faceDown:
// Check the interface orientation
let interfaceOrientation = UIApplication.shared.statusBarOrientation
switch interfaceOrientation{
case .portrait, .portraitUpsideDown:
return true
default:
return false
}
default: // .unknown
return false // not very satisfying to return false as if we were in landscape :-/
}
}
If you are in a ViewController, you can also do like so (that is what I ended up doing):
private var isPortrait: Bool {
let orientation = UIDevice.current.orientation
switch orientation {
case .portrait, .portraitUpsideDown:
return true
case .landscapeLeft, .landscapeRight:
return false
default: // unknown or faceUp or FaceDown
return self.view.width < self.view.height
}
}
Although even this should be enough in that case:
private var isPortrait: Bool {
return self.view.width < self.view.height
}
Swift 5
I got this from another SO answer about 4 yrs ago. I still use it to this day. I don't remember which answer otherwise I would link to it.
Anyway you can use the notification UIDevice.orientationDidChangeNotification:
override func viewDidLoad() {
super.viewDidLoad()
// add this to viewDidLoad
NotificationCenter.default.addObserver(self, selector: #selector(deviceOrientationDidChange),
name: UIDevice.orientationDidChangeNotification,
object: nil)
}
#objc func deviceOrientationDidChange() {
switch UIDevice.current.orientation {
case .landscapeRight:
print("landscapeRight")
case .landscapeLeft:
print("landscapeLeft")
case .portrait:
print("portrait")
case .faceUp:
print("faceUp")
case .faceDown:
print("faceDown")
case .portraitUpsideDown:
print("portraitUpsideDown")
case .unknown:
print("unknown")
default:
print("default")
}
}
Getting the current orientation
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationLandscapeLeft) {
NSLog(#"Landscape left");
self.lblInfo.text = #"Landscape left";
} else if (orientation == UIInterfaceOrientationLandscapeRight) {
NSLog(#"Landscape right");
self.lblInfo.text = #"Landscape right";
} else if (orientation == UIInterfaceOrientationPortrait) {
NSLog(#"Portrait");
self.lblInfo.text = #"Portrait";
} else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
NSLog(#"Upside down");
self.lblInfo.text = #"Upside down";
}
}