Comment détecter correctement le changement d'orientation à l'aide de Phonegap sur iOS?

178

J'ai trouvé ce code de test d'orientation ci-dessous à la recherche de matériel de référence JQTouch. Cela fonctionne correctement dans le simulateur iOS sur Safari mobile mais n'est pas géré correctement dans Phonegap. Mon projet rencontre le même problème qui tue cette page de test. Existe-t-il un moyen de détecter le changement d'orientation à l'aide de JavaScript dans 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;
  }
}
ajpalma
la source

Réponses:

297

C'est ce que je fais:

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();


Mise à jour de mai 2019: window.orientation est une fonctionnalité obsolète et non prise en charge par la plupart des navigateurs selon MDN . L' orientationchangeévénement est associé à window.orientation et ne doit donc probablement pas être utilisé.

Benny Neugebauer
la source
3
C'est la seule solution qui fonctionne pour moi à partir de cette discussion :) +1
Atadj
9
Je l'ai faitwindow.onorientationchange = function() { setTimeout(functionName, 0); };
Kirk Strobeck
11
Par intérêt, pourquoi avez-vous utilisé setTimeout Kirk?
backdesk
10
Faites attention! Ceci est spécifique à l'appareil - les degrés font référence à la différence par rapport à l'orientation standard des appareils. En d'autres termes, si la tablette est conçue pour être utilisée en mode paysage, 90 signifierait qu'elle est en mode portrait. Pour contourner ce problème, je vérifie d'abord la hauteur par rapport à la largeur de la fenêtre pour stocker l'orientation, et j'utilise orientationchange pour mettre à jour cela en cas de changement.
benallansmith
15
De plus, j'ai trouvé que le changement d'orientation se déclenche avant que la largeur et la hauteur ne soient modifiées, donc un peu de retard est nécessaire pour détecter correctement l'orientation en utilisant la largeur et la hauteur. Pour cela, je stocke l'orientation actuelle, et lorsqu'un changement est détecté, je vérifie le changement d'orientation par incréments de 50 ms jusqu'à 250 ms. Une fois qu'une différence est trouvée, je mets à jour la page en conséquence.Sur mon Nexus 5, il détecte généralement la différence entre la largeur et la hauteur après 150 ms.
benallansmith
24

J'utilise window.onresize = function(){ checkOrientation(); } Et dans checkOrientation, vous pouvez utiliser window.orientation ou la vérification de la largeur du corps, mais l'idée est que "window.onresize" est la méthode la plus multi-navigateur, du moins avec la majorité des navigateurs mobiles et de bureau que j'ai possibilité de tester avec.

hndcrftd
la source
1
Ceci est un excellent point. Si vous développez à l'aide d'une technologie Web, cette méthode vous permet de déboguer et de tester plus facilement dans un navigateur au lieu de déployer / simuler à chaque fois.
Matt Ray
2
Ce n'est pas du tout correct ... car lorsque le clavier apparaît, il se redimensionnera (et ce n'est pas le seul cas). Donc un grand non pour ça!
HellBaby
2
@HellBaby Lorsque le clavier apparaît, la fonction sera appelée, cependant, selon la méthode que vous utilisez pour la détection de l'orientation, elle détectera que l'orientation N'A PAS CHANGÉ, comme ce serait le cas avec window.orientation. Donc je reste fidèle à ma réponse.
hndcrftd
1
@Raine J'ai utilisé cette méthode sur un Ipad 4 et j'ai été obligé de la changer à cause de ce problème. Alors peut-être que cela fonctionne pour certains appareils mais pas pour tous ..
HellBaby
1
@MattRay Vous pouvez facilement tester les changements d'orientation avec les dernières boîtes à outils de développement capables d'émuler ce type de comportement de périphérique.
kontur
14
if (window.matchMedia("(orientation: portrait)").matches) {
   // you're in PORTRAIT mode
}

if (window.matchMedia("(orientation: landscape)").matches) {
  // you're in LANDSCAPE mode
}
Alyssa Reyes
la source
1
Vous pouvez le joindre à un resizeévénement. Cependant, IIRC, ces requêtes ne fonctionneront pas correctement avec le clavier en place.
adi518
12

Je suis assez nouveau sur iOS et Phonegap également, mais j'ai pu le faire en ajoutant un eventListener. J'ai fait la même chose (en utilisant l'exemple auquel vous faites référence) et je n'ai pas pu le faire fonctionner. Mais cela semblait faire l'affaire:

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

Vous aurez peut-être un peu de chance en recherchant le terme "orientation" dans le groupe Google PhoneGap .

Un exemple que j'ai lu comme exemple sur la façon de détecter l'orientation était Pie Guy: ( jeu , fichier js ). C'est similaire au code que vous avez publié, mais comme vous ... je n'ai pas pu le faire fonctionner.

Une mise en garde: le eventListener a fonctionné pour moi, mais je ne suis pas sûr qu'il s'agisse d'une approche trop intensive. Jusqu'à présent, c'est la seule façon qui a fonctionné pour moi, mais je ne sais pas s'il existe de meilleures façons plus rationalisées.


UPDATE a corrigé le code ci-dessus, cela fonctionne maintenant

avoision
la source
veuillez corriger le nom de l'événement
Dan
5

Tout en travaillant avec l' orientationchangeévénement, j'avais besoin d'un délai d'attente pour obtenir les dimensions correctes des éléments de la page, mais matchMedia a bien fonctionné. Mon code final:

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)
  });
}
oncode
la source
3

Je crois que la bonne réponse a déjà été publiée et acceptée, mais il y a un problème que j'ai moi-même vécu et que d'autres ont mentionné ici.

Sur certaines plates-formes, diverses propriétés telles que les dimensions de la fenêtre ( window.innerWidth, window.innerHeight) et la window.orientationpropriété ne seront pas mises à jour avant le "orientationchange"déclenchement de l'événement . Plusieurs fois, la propriété window.orientationest undefinedpour quelques millisecondes après le tir de"orientationchange" (au moins c'est dans Chrome sur iOS).

Le meilleur moyen que j'ai trouvé pour gérer ce problème était:

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

Je vérifie si l'orientation n'est pas définie ou si l'orientation est égale à la dernière orientation détectée. Si l'un ou l'autre est vrai, j'attends dix millisecondes, puis j'analyse à nouveau l'orientation. Si l'orientation est une valeur correcte, j'appelle leshowXOrientation fonctions. Si l'orientation n'est pas valide, je continue à boucler ma fonction de vérification, en attendant dix millisecondes à chaque fois, jusqu'à ce qu'elle soit valide.

Maintenant, je créerais un JSFiddle pour cela, comme je le faisais d'habitude, mais JSFiddle ne fonctionnait pas pour moi et mon bug de support a été fermé car personne d'autre ne signale le même problème. Si quelqu'un d'autre veut transformer cela en JSFiddle, veuillez continuer.

Merci! J'espère que ça aide!

WebWanderer
la source
Pour info, lors des tests initiaux, j'ai vu un problème: je fais une rotation dans le sens des aiguilles d'une montre plusieurs fois et une alerte disait "Orientation paysage: 180" même si mon appareil était physiquement orienté comme un portrait.
MarsAndBack
2

Voici ce que j'ai fait:

window.addEventListener('orientationchange', doOnOrientationChange);

function doOnOrientationChange()
{
      if (screen.height > screen.width) {
         console.log('portrait');
      } else {
         console.log('landscape');
      }
}
Raul Gomez
la source
2

Bien que la question ne concerne que l'utilisation de PhoneGap et iOS, et bien qu'elle ait déjà été répondue, je peux ajouter quelques points à la question plus large de la détection de l'orientation de l'écran avec JS en 2019:

  1. window.orientationLa propriété est obsolète et n'est pas prise en charge par les navigateurs Android . Il existe une propriété plus récente qui fournit plus d'informations sur l'orientation - screen.orientation. Mais il est encore expérimental et non pris en charge par iOS Safari . Donc , pour obtenir le meilleur résultat que vous avez probablement besoin d'utiliser la combinaison des deux: const angle = screen.orientation ? screen.orientation.angle : window.orientation.

  2. Comme @benallansmith l'a mentionné dans son commentaire , l' window.onorientationchangeévénement est déclenché avant window.onresize, vous n'obtiendrez donc pas les dimensions réelles de l'écran à moins que vous n'ajoutiez un délai après l'événement orientationchange.

  3. Il existe un plugin d'orientation d'écran Cordova pour prendre en charge les anciens navigateurs mobiles, mais je pense qu'il n'est pas nécessaire de l'utiliser de nos jours.

  4. Il y avait aussi un screen.onorientationchangeévénement, mais il est obsolète et ne doit pas être utilisé. Ajouté juste pour que la réponse soit complète.

Dans mon cas d'utilisation, je ne me souciais pas beaucoup de l'orientation réelle, mais plutôt de la largeur et de la hauteur réelles de la fenêtre, qui changent évidemment avec l'orientation. J'ai donc utilisé l' resizeévénement pour éviter de gérer les délais entre l' orientationchangeévénement et l'actualisation des dimensions de la fenêtre:

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: J'ai utilisé la syntaxe EcmaScript 6 ici, assurez-vous de la compiler vers ES5 si nécessaire.

Remarque 2: l' window.onresizeévénement est également déclenché lorsque le clavier virtuel est basculé , pas seulement lorsque l'orientation change.

Alexey Grinko
la source
1

J'ai trouvé ce code pour détecter si l'appareil est en orientation paysage et, dans ce cas, ajouter une page de garde disant "changer d'orientation pour voir le site". Cela fonctionne sur les téléphones iOS, Android et Windows. Je pense que c'est très utile car c'est assez élégant et évite de définir une vue paysage pour le site mobile. Le code fonctionne très bien. La seule chose qui n'est pas complètement satisfaisante est que si quelqu'un charge la page en mode paysage, la page de démarrage n'apparaît pas.

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

Et le 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>

Luigi
la source
1
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
    }
}
M Fauzi Riozi
la source
-2

Ce qui suit a fonctionné pour moi:

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

J'avais besoin du délai car la valeur de window.orientationne se met pas à jour tout de suite

catalyseur294
la source
-3

Je crée une application jQTouch dans PhoneGap pour iPhone. Je me bats avec ce problème depuis des jours. J'ai vu la solution Eventlistener suggérée à plusieurs reprises, mais je n'ai tout simplement pas pu la faire fonctionner.

En fin de compte, j'ai trouvé une solution différente. Il vérifie essentiellement la largeur du corps périodiquement à l'aide de Settimeout. Si la largeur est de 320 alors l'orientation est portrait, si 480 alors paysage. Ensuite, si l'orientation a changé depuis la dernière vérification, il déclenchera soit une fonction de trucs de portrait, soit une fonction de trucs de paysage où vous pouvez faire ce que vous voulez pour chaque orientation.

Code (note, je sais qu'il y a des répétitions dans le code, je n'ai pas encore pris la peine de le réduire!):

// 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!');
}
Danny Connell
la source
8
Le codage en dur de l'appareil sur 320 ou 480 ne fonctionnera plus à l'avenir, ou avec les téléphones haute résolution actuels.
Fresheyeball
1
1) Vous devez utiliser un onresizeévénement qui se déclenchera immédiatement, pas dans 500 millisecondes 2) Ce code est spécifique à Android, utilisez onorientationchangeplutôt pour iPhone 3) Testez s'il est pris en charge dans le navigateur:"onorientationchange" in window
Dan