How do I correctly detect orientation change using Phonegap on iOS?
Asked Answered
C

12

182

I found this orientation test code below looking for JQTouch reference material. This works correctly in the iOS simulator on mobile Safari but doesn’t get handled correctly in Phonegap. My project is running into the same issue that is killing this test page. Is there a way to sense the orientation change using JavaScript in Phonegap?

window.onorientationchange = function() {
  /*window.orientation returns a value that indicates whether iPhone is in portrait mode, landscape mode with the screen turned to the
    left, or landscape mode with the screen turned to the right. */
  var orientation = window.orientation;
  switch (orientation) {
    case 0:
      /* If in portrait mode, sets the body's class attribute to portrait. Consequently, all style definitions matching the body[class="portrait"] declaration
         in the iPhoneOrientation.css file will be selected and used to style "Handling iPhone or iPod touch Orientation Events". */
      document.body.setAttribute("class", "portrait");

      /* Add a descriptive message on "Handling iPhone or iPod touch Orientation Events"  */
      document.getElementById("currentOrientation").innerHTML = "Now in portrait orientation (Home button on the bottom).";
      break;

    case 90:
      /* If in landscape mode with the screen turned to the left, sets the body's class attribute to landscapeLeft. In this case, all style definitions matching the
         body[class="landscapeLeft"] declaration in the iPhoneOrientation.css file will be selected and used to style "Handling iPhone or iPod touch Orientation Events". */
      document.body.setAttribute("class", "landscape");

      document.getElementById("currentOrientation").innerHTML = "Now in landscape orientation and turned to the left (Home button to the right).";
      break;

    case -90:
      /* If in landscape mode with the screen turned to the right, sets the body's class attribute to landscapeRight. Here, all style definitions matching the
         body[class="landscapeRight"] declaration in the iPhoneOrientation.css file will be selected and used to style "Handling iPhone or iPod touch Orientation Events". */
      document.body.setAttribute("class", "landscape");

      document.getElementById("currentOrientation").innerHTML = "Now in landscape orientation and turned to the right (Home button to the left).";
      break;
  }
}
Conservator answered 12/3, 2011 at 19:26 Comment(1)
possible duplicate of Detect change in orientation using javascriptDaniels
O
298

This is what I do:

function doOnOrientationChange() {
    switch(window.orientation) {  
      case -90: case 90:
        alert('landscape');
        break; 
      default:
        alert('portrait');
        break; 
    }
}
  
window.addEventListener('orientationchange', doOnOrientationChange);
  
// Initial execution if needed
doOnOrientationChange();

Update May 2019: window.orientation is a deprecated feature and not supported by most browsers according to MDN. The orientationchange event is associated with window.orientation and therefore should probably not be used.

Onega answered 22/3, 2012 at 14:39 Comment(19)
That's the only solution that works for me from this discussion :) +1Elemental
I did window.onorientationchange = function() { setTimeout(functionName, 0); };Delvecchio
Out of interest, why did you use setTimeout Kirk?Kea
@Crungmungus It's a hacky way to defer execution. It makes it do it last to ensure it's not getting the orientation before it actually rotates. I am not sure it's necessary, though (i.e. window.orientation should return the new orientation and not what orientation it was at).Ginoginsberg
@Kirk, what about your battery usage now? :)Hower
Note that you can use 180 and 0 as values to get the portrait mode using the same method (in case you want portrait mode explicitly).Audette
I found this helpful, too: function readDeviceOrientation() { if (Math.abs(window.orientation) === 90) { // Landscape } else { // Portrait } } (williammalone.com/articles/html5-javascript-ios-orientation)Ledaledah
there is very good explanation tech-blog.maddyzone.com/javascript/detect-orientation-eventTegantegmen
Be careful! This is device specific - the degrees refer to the difference from the devices standard orientation. In other words, if the tablet is designed to used in landscape, then 90 would mean it's in portrait mode. As a work around to this, I initially check the height vs width of the window to store the orientation, and use orientationchange to update this if there's a change.Mesics
Additionally, I've found that the orientationchange fires before the width and height are changed, therefore a little bit of delay is needed in order to detect the orientation correctly using the width and height. For this, I store the current orientation, and when a change is detected, I check for the change in orientation in 50ms increments upto 250ms. Once a difference is found, I then update the page accordingly.On my Nexus 5, it usually detects the width vs height difference after 150ms.Mesics
I would suggest altering your switch statement as case 0: alert('Portrait'); break; default: alert('Landscape'); break;Milium
definitely buggy on ios8 with safari - sometimes works sometimes not - trying to get a canvas to go full screen after orientation change - width and height values from window are all over the map and alot of delaysLebrun
I have had no problems with this cross device and cross browser solution for portrait and landscape detection. $(window).bind("resize", function(){ screenOrientation = ($(window).width() > $(window).height())? 90 : 0; });Suggs
Binding resize instead of orientationchange allowed me to get rid of my setTimeout. Much better!Specialize
@Mesics How did you set up the wait properly? When I tried using setTimeout it just ran forever, the width/height never changed until it crashed.Hexastich
The || operator shouldn't be used in switch statements unless you are wrapping the whole expression in parentheses. Otherwise, you will not get the behavior you expect.Bookmobile
|| doesn’t work like this in switch. -90 || 90 is equivalent to just -90. You actually need to use case -90: case 90:.Sedum
What if the device was already in portrait mode , how can i check ?Corves
according to mdn, this is not supported by chrome, edge, firefox, internet explorer, opera, and safariTatiania
B
24

I use window.onresize = function(){ checkOrientation(); } And in checkOrientation you can employ window.orientation or body width checking but the idea is, the "window.onresize" is the most cross browser method, at least with the majority of the mobile and desktop browsers that I've had an opportunity to test with.

Blastocoel answered 15/9, 2011 at 23:1 Comment(7)
This is a great point. If you are developing using a web-facing technology, this method allows you to debug and test more easily in a browser instead of deploying/simulating each time.Dosh
This isn't ok at all...cause when the keyboard appears it will resize(and this isn't the only case). So a big no for this!Guesthouse
@Guesthouse When the keyboard appears the function will get called, however, depending on what method you use for orientation detection, it will detect that the orientation HAS NOT CHANGED, as would be the case with window.orientation. So I still stand by my answer.Blastocoel
@Raine I used that method on a Ipad 4 and was forced to change it cause of that issue. So maybe it's working for some devices but not for all..Guesthouse
@Guesthouse So, are you saying that window.orientation returned a conflicting value when the keyboard showed up on the iPad 4 screen? If that is the case, that behavior should be reported as a bug, and your code should be adjusted to account for that specific buggy behavior on that specific platform. I would be interested in finding out what other solution works for iPad 4 if window.orientation is unreliable.Blastocoel
@MattRay You can easily test orientation changes with latest dev toolkits that are capable of emulating this sort of device behavior.Sinus
window.onresize() does not get fired for an ipad air when the orientation changes.Hexastich
K
17
if (window.matchMedia("(orientation: portrait)").matches) {
   // you're in PORTRAIT mode
}

if (window.matchMedia("(orientation: landscape)").matches) {
  // you're in LANDSCAPE mode
}
Kleinstein answered 7/8, 2015 at 6:16 Comment(1)
You can attach it to a resize event. However, IIRC, these queries will not work correctly with the keyboard up.Bufflehead
O
14

I'm pretty new to iOS and Phonegap as well, but I was able to do this by adding in an eventListener. I did the same thing (using the example you reference), and couldn't get it to work. But this seemed to do the trick:

// Event listener to determine change (horizontal/portrait)
window.addEventListener("orientationchange", updateOrientation); 

function updateOrientation(e) {
switch (e.orientation)
{   
    case 0:
        // Do your thing
        break;

    case -90:
        // Do your thing
        break;

    case 90:
        // Do your thing
        break;

    default:
        break;
    }
}

You may have some luck searching the PhoneGap Google Group for the term "orientation".

One example I read about as an example on how to detect orientation was Pie Guy: (game, js file). It's similar to the code you've posted, but like you... I couldn't get it to work.

One caveat: the eventListener worked for me, but I'm not sure if this is an overly intensive approach. So far it's been the only way that's worked for me, but I don't know if there are better, more streamlined ways.


UPDATE fixed the code above, it works now

Obadiah answered 24/3, 2011 at 19:52 Comment(0)
B
10

Although the question refers to only PhoneGap and iOS usage, and although it was already answered, I can add a few points to the broader question of detecting screen orientation with JS in 2019:

  1. window.orientation property is deprecated and not supported by Android browsers.There is a newer property that provides more information about the orientation - screen.orientation. But it is still experimental and not supported by iOS Safari. So to achieve the best result you probably need to use the combination of the two: const angle = screen.orientation ? screen.orientation.angle : window.orientation.

  2. As @benallansmith mentioned in his comment, window.onorientationchange event is fired before window.onresize, so you won't get the actual dimensions of the screen unless you add some delay after the orientationchange event.

  3. There is a Cordova Screen Orientation Plugin for supporting older mobile browsers, but I believe there is no need in using it nowadays.

  4. There was also a screen.onorientationchange event, but it is deprecated and should not be used. Added just for completeness of the answer.

In my use-case, I didn't care much about the actual orientation, but rather about the actual width and height of the window, which obviously changes with orientation. So I used resize event to avoid dealing with delays between orientationchange event and actualizing window dimensions:

window.addEventListener('resize', () => {
  console.log(`Actual dimensions: ${window.innerWidth}x${window.innerHeight}`);
  console.log(`Actual orientation: ${screen.orientation ? screen.orientation.angle : window.orientation}`);
});

Note 1: I used EcmaScript 6 syntax here, make sure to compile it to ES5 if needed.

Note 2: window.onresize event is also fired when virtual keyboard is toggled, not only when orientation changes.

Barmecidal answered 21/11, 2019 at 12:17 Comment(1)
thanks, that sort of saved my behind! I tried with the cordova plugin first, then current-device; but you're totally right, it is ridiculously easy to build it yourself. I made a directive of it and called it a dayWakayama
T
6

While working with the orientationchange event, I needed a timeout to get the correct dimensions of the elements in the page, but matchMedia worked fine. My final code:

var matchMedia = window.msMatchMedia || window.MozMatchMedia || window.WebkitMatchMedia || window.matchMedia;

if (typeof(matchMedia) !== 'undefined') {
  // use matchMedia function to detect orientationchange
  window.matchMedia('(orientation: portrait)').addListener(function() {
    // your code ...
  });
} else {
  // use orientationchange event with timeout (fires to early)
  $(window).on('orientationchange', function() {
    window.setTimeout(function() {
      // your code ...
    }, 300)
  });
}
Thymelaeaceous answered 15/8, 2014 at 7:28 Comment(0)
M
5

I believe that the correct answer has already been posted and accepted, yet there is an issue that I have experienced myself and that some others have mentioned here.

On certain platforms, various properties such as window dimensions (window.innerWidth, window.innerHeight) and the window.orientation property will not be updated by the time that the event "orientationchange" has fired. Many times, the property window.orientation is undefined for a few milliseconds after the firing of "orientationchange" (at least it is in Chrome on iOS).

The best way that I found to handle this issue was:

var handleOrientationChange = (function() {
    var struct = function(){
        struct.parse();
    };
    struct.showPortraitView = function(){
        alert("Portrait Orientation: " + window.orientation);
    };
    struct.showLandscapeView = function(){
        alert("Landscape Orientation: " + window.orientation);
    };
    struct.parse = function(){
        switch(window.orientation){
            case 0:
                    //Portrait Orientation
                    this.showPortraitView();
                break;
            default:
                    //Landscape Orientation
                    if(!parseInt(window.orientation) 
                    || window.orientation === this.lastOrientation)
                        setTimeout(this, 10);
                    else
                    {
                        this.lastOrientation = window.orientation;
                        this.showLandscapeView();
                    }
                break;
        }
    };
    struct.lastOrientation = window.orientation;
    return struct;
})();
window.addEventListener("orientationchange", handleOrientationChange, false);

I am checking to see if the orientation is either undefined or if the orientation is equal to the last orientation detected. If either is true, I wait ten milliseconds and then parse the orientation again. If the orientation is a proper value, I call the showXOrientation functions. If the orientation is invalid, I continue to loop my checking function, waiting ten milliseconds each time, until it is valid.

Now, I would make a JSFiddle for this, as I usually did, but JSFiddle has not been working for me and my support bug for it was closed as no one else is reporting the same problem. If anyone else wants to turn this into a JSFiddle, please go ahead.

Thanks! I hope this helps!

Milium answered 18/3, 2016 at 15:1 Comment(1)
FYI, on initial testing, I saw an issue: I rotate clockwise a couple of times and one alert said "Landscape Orientation: 180" even though my device was physically oriented as a portrait.Gaw
O
3

here is what i did:

window.addEventListener('orientationchange', doOnOrientationChange);

function doOnOrientationChange()
{
      if (screen.height > screen.width) {
         console.log('portrait');
      } else {
         console.log('landscape');
      }
}
Oxalate answered 12/11, 2015 at 18:41 Comment(0)
L
2

I've found this code to detect if the device is in landscape orientation and in this case add a splash page saying "change orientation to see the site". It's working on iOS, android and windows phones. I think that this is very useful since it's quite elegant and avoid to set a landscape view for the mobile site. The code is working very well. The only thing not completely satisfying is that if someone load the page being in landscape view the splash page doesn't appears.

<script>
(function() {
    'use strict';

    var isMobile = {
        Android: function() {
            return navigator.userAgent.match(/Android/i);
        },
        BlackBerry: function() {
            return navigator.userAgent.match(/BlackBerry/i);
        },
        iOS: function() {
            return navigator.userAgent.match(/iPhone|iPad|iPod/i);
        },
        Opera: function() {
            return navigator.userAgent.match(/Opera Mini/i);
        },
        Windows: function() {
            return navigator.userAgent.match(/IEMobile/i);
        },
        any: function() {
            return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows());
        }
    };
    if (isMobile.any()) {
        doOnOrientationChange();
        window.addEventListener('resize', doOnOrientationChange, 'false');
    }

    function doOnOrientationChange() {
        var a = document.getElementById('alert');
        var b = document.body;
        var w = b.offsetWidth;
        var h = b.offsetHeight;
        (w / h > 1) ? (a.className = 'show', b.className = 'full-body') : (a.className = 'hide', b.className = '');
    }
})();
</script>

And the HTML: <div id="alert" class="hide"> <div id="content">This site is not thought to be viewed in landscape mode, please turn your device </div> </div>

Longplaying answered 21/6, 2015 at 15:17 Comment(0)
B
2
if (window.DeviceOrientationEvent) {
    // Listen for orientation changes
    window.addEventListener("orientationchange", orientationChangeHandler);
    function orientationChangeHandler(evt) {
        // Announce the new orientation number
        // alert(screen.orientation);
        // Find matches
        var mql = window.matchMedia("(orientation: portrait)");

        if (mql.matches)  //true
    }
}
Bernicebernie answered 22/5, 2019 at 6:44 Comment(0)
D
-2

The following worked for me:

function changeOrientation(){
switch(window.orientation) {
case 0: // portrait, home bottom
case 180: // portrait, home top
 alert("portrait H: "+$(window).height()+" W: "+$(window).width());       
 break;
          case -90: // landscape, home left
          case 90: // landscape, home right
        alert("landscape H: "+$(window).height()+" W: "+$(window).width());
            break;
        }
    }

 window.onorientationchange = function() { 
            //Need at least 800 milliseconds
            setTimeout(changeOrientation, 1000);
        }

I needed the timeout because the value of window.orientation does not update right away

Darrow answered 12/6, 2012 at 18:36 Comment(0)
H
-3

I'm creating a jQTouch app in PhoneGap for the iPhone. I've been battling with this issue for days. I've seen the eventlistener solution suggested a few times, but just could not get it to work.

In the end I came up with a different solution. It basically checks the width of the body periodically using settimeout. If the width is 320 then the orientation is portrait, if 480 then landscape. Then, if the orientation has changed since the last check, it will fire either a portrait stuff function or a landscape stuff function where you can do your thing for each orientation.

Code (note, I know there is some repetition in the code, just haven't bothered to trim it down yet!):

// get original orientation based on body width
deviceWidth = $('body').width();
if (deviceWidth == 320) {
    currentOrientation = "portrait";
}
else if (deviceWidth == 480) {
    currentOrientation = "landscape";
}

// fire a function that checks the orientation every x milliseconds
setInterval(checkOrientation, 500);

// check orientation
function checkOrientation() {
    deviceWidth = $('body').width();
    if (deviceWidth == '320') {
        newOrientation = "portrait";
    }
    else if (deviceWidth == '480') {
        newOrientation = "landscape";
    }
    // if orientation changed since last check, fire either the portrait or landscape function
    if (newOrientation != currentOrientation) {
        if (newOrientation == "portrait") {
            changedToPortrait();
        }
        else if (newOrientation == "landscape") {
            changedToLandscape();
        }
        currentOrientation = newOrientation;
    }
}

// landscape stuff
function changedToLandscape() {
    alert('Orientation has changed to Landscape!');
}

// portrait stuff
function changedToPortrait() {
    alert('Orientation has changed to Portrait!');
}
Harlanharland answered 16/6, 2011 at 13:49 Comment(2)
Hard coding the device to 320 or 480 will not work in the future, or with current hi-res phones.Levity
1) You should use onresize event that will fire immediately, not in 500 miliseconds 2) This code is android-specific, use onorientationchange instead for iPhone 3) Test if it's supported in the browser: "onorientationchange" in windowHower

© 2022 - 2024 — McMap. All rights reserved.