Detecta la rotación del teléfono Android en el navegador con JavaScript

188

Sé que en Safari en un iPhone puedes detectar la orientación de la pantalla y el cambio de orientación al escuchar el onorientationchangeevento y consultar window.orientationel ángulo.

¿Es esto posible en el navegador en teléfonos Android?

Para ser claros, pregunto si JavaScript puede detectar la rotación de un dispositivo Android que se ejecuta en una página web estándar. Es posible en un iPhone, y me preguntaba si podría hacerse para teléfonos Android.

philnash
fuente

Respuestas:

214

Para detectar un cambio de orientación en un navegador de Android, adjunte un oyente al evento orientationchangeo resizeen window:

// Detect whether device supports orientationchange event, otherwise fall back to
// the resize event.
var supportsOrientationChange = "onorientationchange" in window,
    orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";

window.addEventListener(orientationEvent, function() {
    alert('HOLY ROTATING SCREENS BATMAN:' + window.orientation + " " + screen.width);
}, false);

Verifique la window.orientationpropiedad para determinar en qué dirección está orientado el dispositivo. Con teléfonos Android, screen.widtho screen.heighttambién actualizaciones a medida que se gira el dispositivo. (Este no es el caso con el iPhone).

jb.
fuente
¿Esto realmente funciona? probé jquery $ (ventana) .bind ("orientación cambio", fn); pero no funcionó, ¿tengo que usar el formulario de arriba? Intenté "onorientationchange" en la ventana, se vuelve falso
Ayyash
Funciona bien. Ayyash: todo el punto aquí es que cuando no se admite el "cambio de orientación" volverá a "cambiar el tamaño"
Dror
9
En el Droid esto es completamente loco. Avisa a screen.width de 320 cuando el teléfono gira en modo horizontal, y detecta screen.width 569 cuando gira el teléfono en modo vertical. ¿¿Cómo??
IgorGanapolsky
1
Solo para aclarar: aquellos que busquen una solución que también funcione en iOS deberían mirar a los tontos de dos bits o mi respuesta.
mklement0
3
No es necesario usar el truco de tonto de dos bits para iOS. Simplemente use screen.width y screen.height en Android y en iOS use window.innerWidth y window.innerHeight.
Justin
225

El comportamiento real en diferentes dispositivos es inconsistente . Los eventos de cambio de tamaño y orientación pueden activarse en una secuencia diferente con frecuencia variable. Además, algunos valores (por ejemplo, screen.width y window.orientation) no siempre cambian cuando lo espera. Evite screen.width : no cambia al rotar en iOS.

El enfoque confiable es escuchar los eventos de cambio de tamaño y orientación ( cambiar algunas encuestas como captura de seguridad), y finalmente obtendrá un valor válido para la orientación. En mis pruebas, los dispositivos Android ocasionalmente no disparan eventos cuando giran 180 grados completos, por lo que también he incluido un setInterval para sondear la orientación.

var previousOrientation = window.orientation;
var checkOrientation = function(){
    if(window.orientation !== previousOrientation){
        previousOrientation = window.orientation;
        // orientation changed, do your magic here
    }
};

window.addEventListener("resize", checkOrientation, false);
window.addEventListener("orientationchange", checkOrientation, false);

// (optional) Android doesn't always fire orientationChange on 180 degree turns
setInterval(checkOrientation, 2000);

Aquí están los resultados de los cuatro dispositivos que he probado (perdón por la tabla ASCII, pero parecía la forma más fácil de presentar los resultados). Además de la coherencia entre los dispositivos iOS, existe una gran variedad entre los dispositivos. NOTA: Los eventos se enumeran en el orden en que se dispararon.

| ================================================= ============================= |
El | Dispositivo | Eventos despedidos | orientación | innerWidth | ancho de pantalla |
| ================================================= ============================= |
El | iPad 2 | cambiar el tamaño | 0 | 1024 | 768
El | (al paisaje) | cambio de orientación | 90 1024 | 768
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
El | iPad 2 | cambiar el tamaño | 90 768 768
El | (al retrato) | cambio de orientación | 0 | 768 768
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
El | iPhone 4 | cambiar el tamaño | 0 | 480 320
El | (al paisaje) | cambio de orientación | 90 480 320
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
El | iPhone 4 | cambiar el tamaño | 90 320 320
El | (al retrato) | cambio de orientación | 0 | 320 320
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
El | Teléfono droide | cambio de orientación | 90 320 320
El | (al paisaje) | cambiar el tamaño | 90 569 569
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
El | Teléfono droide | cambio de orientación | 0 | 569 569
El | (al retrato) | cambiar el tamaño | 0 | 320 320
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
El | Samsung Galaxy | cambio de orientación | 0 | 400 | 400 |
El | Tableta | cambio de orientación | 90 400 | 400 |
El | (al paisaje) | cambio de orientación | 90 400 | 400 |
El | El | cambiar el tamaño | 90 683 683
El | El | cambio de orientación | 90 683 683
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
El | Samsung Galaxy | cambio de orientación | 90 683 683
El | Tableta | cambio de orientación | 0 | 683 683
El | (al retrato) | cambio de orientación | 0 | 683 683
El | El | cambiar el tamaño | 0 | 400 | 400 |
El | El | cambio de orientación | 0 | 400 | 400 |
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
tonto de dos bits
fuente
En el emulador iOS5, si actualiza en horizontal y luego gira, este código no se activa.
trabajó
1
Gran respuesta. previousOrientationdebe inicializarse con la orientación actual: var previousOrientation = window.orientation;Si desea ignorar las rotaciones de 180 grados, es decir, no necesita distinguir entre el paisaje izquierdo o derecho y las variantes al revés o no, agregue lo siguiente como primera línea para checkOrientation(): if (0 === (previousOrientation + window.orientation) % 180) return;Sin embargo, sin setTimeouttrucos adicionales , solo se beneficiará de esto en iOS, donde una rotación rápida de 180 grados solo crea un evento único orientationchange .
mklement0
Gracias @mklement, modifiqué el código para inicializar la Orientación anterior.
dos bits tonto
Saludos por la gran información. Esto me estaba molestando porque Windows Phone 8.1 no cuenta con un evento de cambio de tamaño o orientación cuando usas cordova. Recurrió al uso del setInterval también como a prueba de fallos.
Perfección
@ mklement0 Hasta el día de hoy window.orientation siempre estará indefinido en Windows phone 8.1.
Perfección
39

La excelente respuesta de two-bit-fool proporciona todos los antecedentes, pero permítanme intentar un resumen conciso y pragmático de cómo manejar los cambios de orientación en iOS y Android :

  • Si solo le interesan las dimensiones de la ventana (el escenario típico) , y no la orientación específica:
    • Manejar el resize solo evento.
    • En su controlador, actúe window.innerWidthy window.InnerHeightsolo.
    • NO lo use window.orientation: no estará actualizado en iOS.
  • Si te importa la orientación específica :
    • Maneja solo el resizeevento en Android y solo el orientationchangeevento en iOS.
    • En su controlador, actúe sobre window.orientation(y window.innerWidthy window.InnerHeight)

Estos enfoques ofrecen ligeros beneficios sobre recordar la orientación previa y comparar:

  • el enfoque de solo dimensiones también funciona mientras se desarrolla en navegadores de escritorio que de otro modo pueden simular dispositivos móviles, por ejemplo, Chrome 23. ( window.orientationno está disponible en navegadores de escritorio).
  • no es necesaria una variable de nivel global / anónimo-archivo-nivel-función-contenedor
mklement0
fuente
El problema es que cuando cambio de tamaño o evento orientación dispara el window.innerWidth informa dispositivos equivocadas y Droid
albanx
@albanx que sigue siendo un problema en Chrome en ios: / safari está bien aunque
oldboy
12

Siempre puedes escuchar el evento de cambio de tamaño de la ventana. Si, en ese caso, la ventana pasó de ser más alta que ancha a más ancha que alta (o viceversa), puede estar bastante seguro de que la orientación del teléfono se acaba de cambiar.

Joel Mueller
fuente
Esa es una buena idea, voy a tratar de que (y pido a mi amigo con el teléfono Android a prueba!)
philnash
Me acabo de dar cuenta de que este método no me da la orientación del teléfono. Sabré si es vertical u horizontal, pero no si está al revés o si se ha girado hacia la izquierda o hacia la derecha. ¿Alguna otra idea?
philnash el
No estoy seguro de cómo podría importar ... ¿Por qué necesita saber si el teléfono está al revés? El navegador del teléfono tiene una parte superior, y la página web estará orientada a la parte superior del navegador. Cualquier usuario con dos células cerebrales se rocen entre sí que está mirando una página Web al revés acaba de convertir su teléfono en torno a si ellos quieren ver que el lado derecho hacia arriba
Joel Mueller
1
Eso es un poco duro. Me interesa saber para poder mostrar contenido diferente en función de la orientación de la pantalla, esto podría ser hasta 4 páginas diferentes, lo que requiere que el navegador sepa si se ha girado 0, 90, 180 y 270 grados. Todo esto es posible, en JavaScript, en el iPhone y es por eso que pregunto.
philnash el
Todavía me cuesta imaginar lo que una página web podría hacer de manera diferente cuando el dispositivo en el que se procesa gira 270 grados, pero si dices que tienes un caso de uso válido, no dudaré. En ese caso: lo siento, pero no tengo idea si el navegador de Android proporciona este nivel de detalle.
Joel Mueller el
3

Es posible en HTML5.
Puede leer más (y probar una demostración en vivo) aquí: http://slides.html5rocks.com/#slide-orientation .

window.addEventListener('deviceorientation', function(event) {
    var a = event.alpha;
    var b = event.beta;
    var g = event.gamma;
}, false);

También es compatible con los navegadores de escritorio, pero siempre devolverá el mismo valor.

Derek 朕 會 功夫
fuente
44
Este evento es realmente más para acceder a los sensores de movimiento, aunque supongo que también se puede usar para detectar cambios de orientación.
René
En mi Android Galaxy S2 no es compatible con el navegador estándar ni con el navegador Dolphin. Pero funciona bien con Firefox móvil.
Eduardo
3

Yo tuve el mismo problema. Estoy usando Phonegap y Jquery mobile, para dispositivos Adroid. Para cambiar el tamaño correctamente, tuve que establecer un tiempo de espera:

$(window).bind('orientationchange',function(e) {
  fixOrientation();
});

$(window).bind('resize',function(e) {
  fixOrientation();
});

function fixOrientation() {

    setTimeout(function() {

        var windowWidth = window.innerWidth;

        $('div[data-role="page"]').width(windowWidth);
        $('div[data-role="header"]').width(windowWidth);
        $('div[data-role="content"]').width(windowWidth-30);
        $('div[data-role="footer"]').width(windowWidth);

    },500);
}
tauanz
fuente
2

Aquí está la solución:

var isMobile = {
    Android: function() {
        return /Android/i.test(navigator.userAgent);
    },
    iOS: function() {
        return /iPhone|iPad|iPod/i.test(navigator.userAgent);
    }
};
if(isMobile.Android())
    {
        var previousWidth=$(window).width();
        $(window).on({
        resize: function(e) {
        var YourFunction=(function(){

            var screenWidth=$(window).width();
            if(previousWidth!=screenWidth)
            {
                previousWidth=screenWidth;
                alert("oreientation changed");
            }

        })();

        }
    });

    }
    else//mainly for ios
    {
        $(window).on({
            orientationchange: function(e) {
               alert("orientation changed");
            }   
        });
    }
Shishir Arora
fuente
Esta es la solución que mejor funcionó para mí, sé que no es 100% precisa, pero puede detectar horizontal vs vertical usando esto: var screenWidth = $ (window) .width (); var screenHeight = $ (ventana) .height (); if (screenWidth> screenHeight) {doSomething (); }
math0ne
Esta fue la solución para mí en una mala tableta de Android. window.onresize, attachevent y addeventlistener fallaron en múltiples eventos (cambio de tamaño, cambio de tamaño, cambio de orientación, orientación del dispositivo). Solo Jquery $ (window) .on () funcionó.
Lego
1

Otro problema: algunas tabletas Android (creo que la Motorola Xoom y una Elonex de gama baja en las que estoy haciendo algunas pruebas, probablemente otras también) tienen sus acelerómetros configurados de modo que window.orientation == 0 en modo PAISAJE, no vertical !

james-geldart
fuente
1

puedes probar la solución, compatible con todos los navegadores.

A continuación se muestra una orientationchangeimagen de compatibilidad: compatibilidad por lo tanto, autor de un orientaionchangepolyfill, se basa en el atributo @media para corregir la biblioteca de utilidad de orientación de cambio—— orientación de cambio de orientación

window.addEventListener('orientationchange', function(){
 if(window.neworientation.current === 'portrait|landscape'){
    // do something……
 } else {
    // do something……
 }
}, false);
Zhansingsong
fuente
0

Vale la pena señalar que en mi Epic 4G Touch tuve que configurar la vista web para usar WebChromeClient antes de que funcionara cualquiera de las llamadas de Android javascript.

webView.setWebChromeClient(new WebChromeClient());
calebisstupido
fuente
0

Navegador cruzado

$(window).on('resize orientationchange webkitfullscreenchange mozfullscreenchange fullscreenchange',  function(){
//code here
});
comonitos
fuente
-1

Una pequeña contribución a la respuesta del tonto de dos bits:

Como se describe en la tabla en los teléfonos droides, el evento de "cambio de orientación" se dispara antes que el evento de "cambio de tamaño", lo que bloquea la siguiente llamada de cambio de tamaño (debido a la declaración if). La propiedad de ancho todavía no está establecida.

Una solución alternativa, aunque tal vez no sea perfecta, podría ser no disparar el evento de "cambio de orientación". Eso se puede archivar envolviendo el enlace de evento "orientación cambio" en la declaración "if":

if (!navigator.userAgent.match(/android/i))
{
    window.addEventListener("orientationchange", checkOrientation, false);
}

Espero eso ayude

(las pruebas se realizaron en Nexus S)

Alex
fuente