¿Cómo detecto correctamente el cambio de orientación usando Phonegap en iOS?

178

Encontré este código de prueba de orientación a continuación buscando material de referencia JQTouch. Esto funciona correctamente en el simulador de iOS en Safari móvil, pero no se maneja correctamente en Phonegap. Mi proyecto se encuentra con el mismo problema que está matando esta página de prueba. ¿Hay alguna manera de sentir el cambio de orientación usando JavaScript en 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
fuente

Respuestas:

297

Esto es lo que hago:

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


Actualización de mayo de 2019: window.orientation es una característica obsoleta y no es compatible con la mayoría de los navegadores de acuerdo con MDN . El orientationchangeevento está asociado con window.orientation y, por lo tanto, probablemente no debería usarse.

Benny Neugebauer
fuente
3
Esa es la única solución que me funciona de esta discusión :) +1
Atadj
9
Lo hicewindow.onorientationchange = function() { setTimeout(functionName, 0); };
Kirk Strobeck
11
Por interés, ¿por qué usaste setTimeout Kirk?
backdesk
10
¡Ten cuidado! Esto es específico del dispositivo: los grados se refieren a la diferencia con respecto a la orientación estándar del dispositivo. En otras palabras, si la tableta está diseñada para usarse en horizontal, 90 significaría que está en modo vertical. Como solución a esto, inicialmente verifico el alto frente al ancho de la ventana para almacenar la orientación, y uso el cambio de orientación para actualizar esto si hay un cambio.
benallansmith
15
Además, descubrí que el cambio de orientación se dispara antes de cambiar el ancho y la altura, por lo tanto, se necesita un poco de retraso para detectar la orientación correctamente usando el ancho y la altura. Para esto, almaceno la orientación actual, y cuando se detecta un cambio, verifico el cambio de orientación en incrementos de 50 ms hasta 250 ms. Una vez que se encuentra una diferencia, actualizo la página en consecuencia. En mi Nexus 5, generalmente detecta la diferencia de ancho frente a altura después de 150 ms.
benallansmith
24

Yo uso window.onresize = function(){ checkOrientation(); } Y en checkOrientation puedes emplear window.orientation o body width testing pero la idea es que "window.onresize" es el método de navegador más cruzado, al menos con la mayoría de los navegadores móviles y de escritorio que he tenido oportunidad de probar con.

hndcrftd
fuente
1
Es un excelente punto. Si está desarrollando utilizando una tecnología orientada a la web, este método le permite depurar y probar más fácilmente en un navegador en lugar de implementar / simular cada vez.
Matt Ray
2
Esto no está bien en absoluto ... porque cuando aparece el teclado cambiará de tamaño (y este no es el único caso). ¡Entonces un gran no por esto!
HellBaby
2
@HellBaby Cuando aparezca el teclado, se llamará a la función, sin embargo, dependiendo del método que use para la detección de orientación, detectará que la orientación NO HA CAMBIADO, como sería el caso con window.orientation. Así que aún mantengo mi respuesta.
hndcrftd
1
@Raine Usé ese método en un Ipad 4 y me vi obligado a cambiarlo debido a ese problema. Así que tal vez esté funcionando para algunos dispositivos, pero no para todos ...
HellBaby
1
@MattRay Puede probar fácilmente los cambios de orientación con los últimos kits de herramientas de desarrollo que son capaces de emular este tipo de comportamiento 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
}
Alyssa Reyes
fuente
1
Puedes adjuntarlo a un resizeevento. Sin embargo, IIRC, estas consultas no funcionarán correctamente con el teclado arriba.
adi518
12

Soy bastante nuevo en iOS y Phonegap también, pero pude hacer esto agregando un eventListener. Hice lo mismo (usando el ejemplo al que hace referencia), y no pude hacerlo funcionar. Pero esto parecía hacer el truco:

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

Es posible que tenga suerte buscando en el grupo PhoneGap Google el término "orientación" .

Un ejemplo del que leí como ejemplo sobre cómo detectar la orientación fue Pie Guy: ( juego , archivo js ). Es similar al código que has publicado, pero como tú ... No pude hacerlo funcionar.

Una advertencia: el EventListener funcionó para mí, pero no estoy seguro de si este es un enfoque demasiado intensivo. Hasta ahora ha sido la única forma que me ha funcionado, pero no sé si hay formas mejores y más optimizadas.


ACTUALIZACIÓN arregló el código anterior, funciona ahora

Avoision
fuente
plese arregle el nombre del evento
Dan
5

Mientras trabajaba con el orientationchangeevento, necesitaba un tiempo de espera para obtener las dimensiones correctas de los elementos en la página, pero matchMedia funcionó bien. Mi codigo 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
fuente
3

Creo que la respuesta correcta ya ha sido publicada y aceptada, sin embargo, hay un problema que he experimentado yo mismo y que otros han mencionado aquí.

En ciertas plataformas, varias propiedades como las dimensiones de la ventana ( window.innerWidth, window.innerHeight) y la window.orientationpropiedad no se actualizarán cuando se active el evento "orientationchange". Muchas veces, la propiedad window.orientationes undefinedpor unos pocos milisegundos después del disparo de"orientationchange" (al menos está en Chrome en iOS).

La mejor manera que encontré para manejar este problema fue:

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

Estoy comprobando si la orientación no está definida o si la orientación es igual a la última orientación detectada. Si cualquiera de los dos es cierto, espero diez milisegundos y luego vuelvo a analizar la orientación. Si la orientación es un valor apropiado, llamo alshowXOrientation funciones. Si la orientación no es válida, continúo haciendo un bucle en mi función de verificación, esperando diez milisegundos cada vez, hasta que sea válida.

Ahora, haría un JSFiddle para esto, como solía hacerlo, pero JSFiddle no ha funcionado para mí y mi error de soporte se cerró ya que nadie más informa el mismo problema. Si alguien más quiere convertir esto en un JSFiddle, adelante.

¡Gracias! ¡Espero que esto ayude!

WebWanderer
fuente
Para su información, en la prueba inicial, vi un problema: gire en el sentido de las agujas del reloj un par de veces y una alerta decía "Orientación horizontal: 180" a pesar de que mi dispositivo estaba orientado físicamente como un retrato.
MarsAndBack
2

Aquí esta lo que hice:

window.addEventListener('orientationchange', doOnOrientationChange);

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

Aunque la pregunta se refiere solo al uso de PhoneGap e iOS, y aunque ya fue respondida, puedo agregar algunos puntos a la pregunta más amplia de detectar la orientación de la pantalla con JS en 2019:

  1. window.orientationla propiedad está en desuso y no es compatible con los navegadores de Android . Hay una propiedad más nueva que proporciona más información sobre la orientación - screen.orientation. Pero todavía es experimental y no es compatible con iOS Safari . Así que para conseguir el mejor resultado es probable que tenga que utilizar la combinación de los dos: const angle = screen.orientation ? screen.orientation.angle : window.orientation.

  2. Como @benallansmith mencionó en su comentario , el window.onorientationchangeevento se dispara antes window.onresize, por lo que no obtendrá las dimensiones reales de la pantalla a menos que agregue algún retraso después del evento de cambio de orientación.

  3. Existe un complemento de orientación de pantalla de Cordova para admitir navegadores móviles más antiguos, pero creo que no hay necesidad de usarlo hoy en día.

  4. También hubo un screen.onorientationchangeevento, pero está en desuso y no debe usarse. Agregado solo para completar la respuesta.

En mi caso de uso, no me importaba mucho la orientación real, sino más bien el ancho y la altura reales de la ventana, que obviamente cambia con la orientación. Así que usé el resizeevento para evitar lidiar con retrasos entre el orientationchangeevento y la actualización de las dimensiones de la ventana:

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: Utilicé la sintaxis de EcmaScript 6 aquí, asegúrese de compilarlo en ES5 si es necesario.

Nota 2: el window.onresizeevento también se activa cuando se alterna el teclado virtual , no solo cuando cambia la orientación.

Alexey Grinko
fuente
1

Encontré este código para detectar si el dispositivo está en orientación horizontal y en este caso agrego una página de bienvenida que dice "cambiar orientación para ver el sitio". Funciona en teléfonos iOS, Android y Windows. Creo que esto es muy útil ya que es bastante elegante y evito establecer una vista horizontal para el sitio móvil. El código funciona muy bien. Lo único que no es completamente satisfactorio es que si alguien carga la página en vista horizontal, la página de bienvenida no aparece.

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

Y el 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
fuente
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
fuente
-2

Lo siguiente funcionó para mí:

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

Necesitaba el tiempo de espera porque el valor de window.orientationno se actualiza de inmediato

catalizador294
fuente
-3

Estoy creando una aplicación jQTouch en PhoneGap para iPhone. He estado luchando con este problema durante días. He visto la solución eventlistener sugerida varias veces, pero simplemente no pude hacer que funcione.

Al final se me ocurrió una solución diferente. Básicamente verifica el ancho del cuerpo periódicamente usando settimeout. Si el ancho es 320, entonces la orientación es vertical, si 480 es horizontal. Luego, si la orientación ha cambiado desde la última verificación, activará una función de material vertical o una función de material horizontal donde puede hacer lo suyo para cada orientación.

Código (nota, sé que hay una cierta repetición en el código, ¡simplemente no me he molestado en recortarlo todavía!):

// 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
fuente
8
La codificación dura del dispositivo a 320 o 480 no funcionará en el futuro, o con los teléfonos de alta resolución actuales.
Fresheyeball
1
1) Debe usar el onresizeevento que se disparará inmediatamente, no en 500 milisegundos 2) Este código es específico de Android, use onorientationchangeen su lugar para iPhone 3) Pruebe si es compatible con el navegador:"onorientationchange" in window
Dan