Come posso rilevare correttamente il cambio di orientamento usando Phonegap su iOS?


178

Ho trovato questo codice di test di orientamento di seguito alla ricerca di materiale di riferimento JQTouch. Funziona correttamente nel simulatore iOS su Safari mobile ma non viene gestito correttamente in Phonegap. Il mio progetto sta riscontrando lo stesso problema che sta uccidendo questa pagina di test. C'è un modo per rilevare il cambiamento di orientamento usando 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;
  }
}

Risposte:


297

Questo è ciò che faccio:

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


Aggiornamento maggio 2019: window.orientation è una funzionalità obsoleta e non supportata dalla maggior parte dei browser secondo MDN . L' orientationchangeevento è associato a window.orientation e quindi probabilmente non dovrebbe essere usato.


3
Questa è l'unica soluzione che funziona per me da questa discussione :) +1
Atadj

9
L'ho fattowindow.onorientationchange = function() { setTimeout(functionName, 0); };
Kirk Strobeck il

11
Per interesse, perché hai usato setTimeout Kirk?
backdesk,

10
Stai attento! Questo è specifico del dispositivo: i gradi si riferiscono alla differenza rispetto all'orientamento standard dei dispositivi. In altre parole, se il tablet è progettato per essere utilizzato in orizzontale, 90 significherebbe che è in modalità verticale. Per ovviare a questo, inizialmente controllo l'altezza rispetto alla larghezza della finestra per memorizzare l'orientamento e uso l'orientamento cambia per aggiornarlo se c'è una modifica.
benallansmith,

15
Inoltre, ho scoperto che il cambio di orientamento si attiva prima che la larghezza e l'altezza vengano modificate, quindi è necessario un po 'di ritardo per rilevare correttamente l'orientamento usando la larghezza e l'altezza. Per questo, memorizzo l'orientamento corrente e quando viene rilevata una modifica, controllo la modifica dell'orientamento con incrementi di 50 ms fino a 250 ms. Una volta trovata una differenza, aggiorno la pagina di conseguenza. Sul mio Nexus 5, di solito rileva la differenza di larghezza vs altezza dopo 150 ms.
benallansmith,

24

Io uso window.onresize = function(){ checkOrientation(); } E in checkOrientation puoi usare window.orientation o controllo della larghezza del corpo ma l'idea è che "window.onresize" è il metodo più cross-browser, almeno con la maggior parte dei browser mobili e desktop che ho avuto possibilità di testare con.


1
Questo è un ottimo punto. Se si sta sviluppando utilizzando una tecnologia Web, questo metodo consente di eseguire il debug e testare più facilmente in un browser invece di distribuire / simulare ogni volta.
Matt Ray,

2
Questo non va affatto bene ... perché quando appare la tastiera si ridimensionerà (e questo non è l'unico caso). Quindi un grande no per questo!
HellBaby,

2
@HellBaby Quando appare la tastiera, la funzione verrà chiamata, tuttavia, a seconda del metodo utilizzato per il rilevamento dell'orientamento, rileverà che l'orientamento NON È CAMBIATO, come nel caso di window.orientation. Quindi resto ancora dalla mia risposta.
hndcrftd,

1
@Raine Ho usato quel metodo su un Ipad 4 e sono stato costretto a cambiarlo a causa di quel problema. Quindi forse funziona per alcuni dispositivi, ma non per tutti ..
HellBaby,

1
@MattRay È possibile testare facilmente i cambiamenti di orientamento con gli ultimi kit di strumenti di sviluppo in grado di emulare questo tipo di comportamento del dispositivo.
Kontur,

14
if (window.matchMedia("(orientation: portrait)").matches) {
   // you're in PORTRAIT mode
}

if (window.matchMedia("(orientation: landscape)").matches) {
  // you're in LANDSCAPE mode
}

1
Puoi collegarlo a un resizeevento. Tuttavia, IIRC, queste query non funzioneranno correttamente con la tastiera in alto.
adi518,

12

Sono abbastanza nuovo anche per iOS e Phonegap, ma sono stato in grado di farlo aggiungendo un listener di eventi. Ho fatto la stessa cosa (usando l'esempio a cui fai riferimento) e non sono riuscito a farlo funzionare. Ma questo sembrava fare il trucco:

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

Potresti avere un po 'di fortuna cercando nel gruppo Google PhoneGap il termine "orientamento" .

Un esempio che ho letto come esempio su come rilevare l'orientamento era Pie Guy: ( gioco , file js ). È simile al codice che hai pubblicato, ma come te ... Non sono riuscito a farlo funzionare.

Un avvertimento: eventListener ha funzionato per me, ma non sono sicuro che si tratti di un approccio eccessivamente intenso. Finora è stato l'unico modo che ha funzionato per me, ma non so se ci siano modi migliori e più snelli.


UPDATE risolto il codice sopra, funziona ora


si prega di fissare il nome dell'evento
Dan

5

Mentre lavoravo con l' orientationchangeevento, avevo bisogno di un timeout per ottenere le dimensioni corrette degli elementi nella pagina, ma matchMedia ha funzionato bene. Il mio codice finale:

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

3

Credo che la risposta corretta sia già stata pubblicata e accettata, eppure c'è un problema che ho sperimentato me stesso e che alcuni altri hanno menzionato qui.

Su alcune piattaforme, varie proprietà come le dimensioni della finestra ( window.innerWidth, window.innerHeight) e la window.orientationproprietà non verranno aggiornate al momento dell'attivazione dell'evento "orientationchange". Molte volte, la proprietà window.orientationè undefinedper alcuni millisecondi dopo l'incendio di"orientationchange" (almeno è in Chrome su iOS).

Il modo migliore che ho trovato per gestire questo problema è stato:

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

Sto verificando se l'orientamento non è definito o se l'orientamento è uguale all'ultimo orientamento rilevato. Se uno dei due è vero, aspetto dieci millisecondi e quindi analizzo nuovamente l'orientamento. Se l'orientamento è un valore corretto, chiamo ilshowXOrientation funzioni. Se l'orientamento non è valido, continuo a eseguire il ciclo della mia funzione di controllo, aspettando dieci millisecondi ogni volta, fino a quando non è valido.

Ora, farei un JSFiddle per questo, come facevo di solito, ma JSFiddle non ha funzionato per me e il mio bug di supporto è stato chiuso poiché nessun altro ha segnalato lo stesso problema. Se qualcun altro vuole trasformarlo in un JSFiddle, vai avanti.

Grazie! Spero che aiuti!


Cordiali saluti, durante i test iniziali, ho riscontrato un problema: giro un paio di volte in senso orario e un avviso diceva "Orientamento orizzontale: 180" anche se il mio dispositivo era orientato fisicamente come ritratto.
MarsAndBack

2

ecco cosa ho fatto:

window.addEventListener('orientationchange', doOnOrientationChange);

function doOnOrientationChange()
{
      if (screen.height > screen.width) {
         console.log('portrait');
      } else {
         console.log('landscape');
      }
}

2

Sebbene la domanda si riferisca solo all'utilizzo di PhoneGap e iOS e sebbene abbia già ricevuto risposta, posso aggiungere alcuni punti alla domanda più ampia di rilevare l'orientamento dello schermo con JS nel 2019:

  1. window.orientationproprietà è obsoleta e non supportata dai browser Android . Esiste una proprietà più recente che fornisce ulteriori informazioni sull'orientamento - screen.orientation. Ma è ancora sperimentale e non supportato da iOS Safari . Quindi, per ottenere il miglior risultato probabilmente è necessario utilizzare la combinazione dei due: const angle = screen.orientation ? screen.orientation.angle : window.orientation.

  2. Come menzionato da @benallansmith nel suo commento , l' window.onorientationchangeevento viene generato in precedenza window.onresize, quindi non otterrai le dimensioni effettive dello schermo a meno che tu non aggiunga qualche ritardo dopo l'evento di orientamento.

  3. Esiste un plug-in Cordova per l'orientamento dello schermo per supportare i browser mobili meno recenti, ma credo che non sia necessario utilizzarlo al giorno d'oggi.

  4. Si è verificato anche un screen.onorientationchangeevento, ma è obsoleto e non deve essere utilizzato. Aggiunto solo per completezza della risposta.

Nel mio caso d'uso, non mi importava molto dell'orientamento reale, ma piuttosto della larghezza e altezza effettive della finestra, che ovviamente cambia con l'orientamento. Quindi ho usato l' resizeevento per evitare di gestire i ritardi tra l' orientationchangeevento e attualizzare le dimensioni della finestra:

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

Nota 1: Ho usato la sintassi EcmaScript 6 qui, assicurati di compilarlo in ES5 se necessario.

Nota 2: l' window.onresizeevento viene generato anche quando viene attivata la tastiera virtuale , non solo quando cambia l'orientamento.


1

Ho trovato questo codice per rilevare se il dispositivo è in orientamento orizzontale e in questo caso aggiungere una splash page che dice "cambia orientamento per vedere il sito". Funziona su iOS, Android e Windows Phone. Penso che questo sia molto utile poiché è abbastanza elegante ed evita di impostare una vista orizzontale per il sito mobile. Il codice funziona molto bene. L'unica cosa che non è completamente soddisfacente è che se qualcuno carica la pagina in modalità orizzontale, la pagina iniziale non viene visualizzata.

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

E l'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>


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

-2

Per me ha funzionato:

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

Avevo bisogno del timeout perché il valore di window.orientationnon si aggiorna immediatamente


-3

Sto creando un'app jQTouch in PhoneGap per iPhone. Ho combattuto con questo problema per giorni. Ho visto la soluzione eventlistener suggerita alcune volte, ma non sono riuscita a farlo funzionare.

Alla fine ho trovato una soluzione diversa. In pratica controlla periodicamente la larghezza del corpo usando il settimeout. Se la larghezza è 320, l'orientamento è verticale, se 480 quindi orizzontale. Quindi, se l'orientamento è cambiato dall'ultimo controllo, verrà attivata una funzione di ritratto o una funzione di paesaggio in cui è possibile eseguire le operazioni per ciascun orientamento.

Codice (nota, so che c'è qualche ripetizione nel codice, ma non mi sono ancora preoccupato di eliminarlo!):

// 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!');
}

8
La codifica hardware del dispositivo su 320 o 480 non funzionerà in futuro o con gli attuali telefoni ad alta risoluzione.
Fresheyeball,

1
1) Dovresti usare un onresizeevento che si attiverà immediatamente, non tra 500 millisecondi 2) Questo codice è specifico per Android, usa onorientationchangeinvece per iPhone 3) Verifica se è supportato nel browser:"onorientationchange" in window
Dan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.