Detectar rotação do telefone Android no navegador com JavaScript

187

Eu sei que no Safari em um iPhone você pode detectar a orientação da tela e mudar de orientação ouvindo o onorientationchangeevento e consultando window.orientationo ângulo.

Isso é possível no navegador de telefones Android?

Para esclarecer, pergunto se a rotação de um dispositivo Android pode ser detectada pelo JavaScript em execução em uma página da web padrão. É possível em um iPhone, e me perguntei se isso poderia ser feito para telefones Android.

philnash
fonte

Respostas:

214

Para detectar uma alteração de orientação em um navegador Android, anexe um ouvinte ao evento orientationchangeou resizeem 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 a window.orientationpropriedade para descobrir em que direção o dispositivo está orientado. Com telefones Android, screen.widthou screen.heighttambém atualiza conforme o dispositivo é rotacionado. (esse não é o caso do iPhone).

jb.
fonte
isso realmente funciona? Eu tentei jquery $ (window) .bind ("orientedchange", fn); mas não funcionou, tenho que usar o formulário acima? Eu tentei "onorientationchange" na janela, ele é falso novamente
Ayyash
Isso funciona bem. Ayyash - o ponto inteiro aqui que quando "orientationChange" não é suportado ele vai cair de volta para "redimensionamento"
Dror
9
No Droid, isso é completamente insano. Alerta a largura de tela de 320 quando o telefone é girado no modo paisagem e detecta a largura de tela 569 quando o telefone é girado no modo de retrato! Por quê??
IgorGanapolsky
1
Só para esclarecer: quem procura uma solução que também funcione no iOS deve considerar a resposta de dois bits ou a minha.
mklement0
3
Não é necessário usar o truque de dois bits para o iOS. Basta usar screen.width e screen.height no Android e no iOS e use window.innerWidth e window.innerHeight.
Justin
224

O comportamento real em diferentes dispositivos é inconsistente . Os eventos redimensionar e guidanceChange podem ser disparados em uma sequência diferente com frequência variável. Além disso, alguns valores (por exemplo, screen.width e window.orientation) nem sempre mudam quando você espera. Evite screen.width - ele não muda ao girar no iOS.

A abordagem confiável é ouvir os eventos de redimensionamento e de orientação e alterar (com algumas pesquisas como uma captura de segurança) e, eventualmente, você obterá um valor válido para a orientação. Nos meus testes, os dispositivos Android ocasionalmente falham em disparar eventos ao girar 180 graus, por isso também incluí um setInterval para pesquisar a orientação.

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

Aqui estão os resultados dos quatro dispositivos que testei (desculpe pela tabela ASCII, mas parecia a maneira mais fácil de apresentar os resultados). Além da consistência entre os dispositivos iOS, há muita variedade entre os dispositivos. NOTA: Os eventos são listados na ordem em que foram disparados.

| =================================================== ============================= |
| Dispositivo | Eventos demitidos | orientação | innerWidth | screen.width |
| =================================================== ============================= |
| iPad 2 | redimensionar | 0 1024 768
| (para paisagem) | mudança de orientação | 90 1024 768
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
| iPad 2 | redimensionar | 90 768 768
| (para retrato) | mudança de orientação | 0 768 768
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
| iPhone 4 | redimensionar | 0 480 320
| (para paisagem) | mudança de orientação | 90 480 320
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
| iPhone 4 | redimensionar | 90 320 320
| (para retrato) | mudança de orientação | 0 320 320
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
| Telefone droid | mudança de orientação | 90 320 320
| (para paisagem) | redimensionar | 90 569 569
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
| Telefone droid | mudança de orientação | 0 569 569
| (para retrato) | redimensionar | 0 320 320
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
| Samsung Galaxy | mudança de orientação | 0 400 400
| Tablet | mudança de orientação | 90 400 400
| (para paisagem) | mudança de orientação | 90 400 400
| | redimensionar | 90 683 683
| | mudança de orientação | 90 683 683
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
| Samsung Galaxy | mudança de orientação | 90 683 683
| Tablet | mudança de orientação | 0 683 683
| (para retrato) | mudança de orientação | 0 683 683
| | redimensionar | 0 400 400
| | mudança de orientação | 0 400 400
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
idiota
fonte
No emulador iOS5, se você atualizar no modo paisagem e girar, esse código não será acionado.
trabalhou
1
Ótima resposta. previousOrientationdeve ser inicializado com a orientação atual: var previousOrientation = window.orientation;Se você deseja ignorar rotações de 180 graus, ou seja, não precisa distinguir entre a paisagem esquerda ou direita e as variantes de cabeça para baixo ou não, adicione o seguinte como a primeira linha para checkOrientation(): if (0 === (previousOrientation + window.orientation) % 180) return;No entanto, sem setTimeouttruques adicionais , você se beneficiará disso apenas no iOS, onde uma rotação rápida de 180 graus cria apenas um único orientationchange evento.
mklement0
Obrigado @mklement, alterei o código para inicializar aOrientação anterior.
2-
Felicidades pela grande informação. Isso estava acontecendo porque o windows phone 8.1 não apresenta um evento de redimensionamento ou mudança de orientação quando você usa o cordova. Recorreu ao uso de setInterval e também como à prova de falhas.
Perfeição
@ mklement0 Até hoje, a window.orientation estará sempre indefinida no windows phone 8.1.
perfeição
39

A excelente resposta do tolo de dois bits fornece todo o pano de fundo, mas deixe-me tentar um resumo conciso e pragmático de como lidar com as mudanças de orientação no iOS e no Android :

  • Se você se importa apenas com as dimensões da janela (o cenário típico) - e não com a orientação específica:
    • Manipule resizeapenas o evento.
    • Em seu manipulador, agir sobre window.innerWidthe window.InnerHeightúnica.
    • NÃO use window.orientation- não será atualizado no iOS.
  • Se você se importa com a orientação específica :
    • Manipule apenas o resizeevento no Android e somente o orientationchangeevento no iOS.
    • No seu manipulador, atue em window.orientation(e window.innerWidthe window.InnerHeight)

Essas abordagens oferecem pequenos benefícios sobre a lembrança da orientação anterior e a comparação:

  • a abordagem apenas de dimensões também funciona durante o desenvolvimento em navegadores de desktop que, de outra forma, podem simular dispositivos móveis, por exemplo, Chrome 23. ( window.orientationnão está disponível em navegadores de desktop).
  • não há necessidade de uma variável global / anônima no nível do arquivo, no nível da função do wrapper.
mklement0
fonte
O problema é que quando redimensionamento ou evento orientação dispara o window.innerWidth relata dispositivos erradas e Droid
albanx
@albanx que ainda é um problema no Chrome no iOS: / safari é bom tho
Oldboy
12

Você sempre pode ouvir o evento de redimensionamento da janela. Se, nesse caso, a janela passou de mais alta do que larga para mais larga do que alta (ou vice-versa), você pode ter certeza de que a orientação do telefone foi alterada.

Joel Mueller
fonte
Essa é uma boa idéia, eu vou tentar isso (e pedir ao meu amigo com o telefone Android para teste!)
philnash
Acabei de perceber que esse método não me dá a orientação do telefone. Vou saber se é retrato ou paisagem, mas não se estiver de cabeça para baixo ou se tiver sido virado para a esquerda ou para a direita. Alguma idéia adicional?
philnash
Não sei ao certo como isso poderia importar ... Por que você precisa saber se o telefone está de cabeça para baixo? O navegador do telefone possui uma parte superior e a página da Web será orientada para a parte superior do navegador. Qualquer usuário com duas células cerebrais para esfregar juntos que está olhando para uma página web de cabeça para baixo só vai transformar seu telefone em volta se eles querem vê-lo do lado direito para cima
Joel Mueller
1
Isso é um pouco duro. Estou interessado em saber, para que eu possa mostrar conteúdo diferente com base na orientação da tela, isso pode ter até 4 páginas diferentes, exigindo que o navegador saiba se ele foi girado em 0, 90, 180 e 270 graus. Tudo isso é possível, em JavaScript, no iPhone e é por isso que estou perguntando.
5609 philnash #
Ainda estou com dificuldade para imaginar o que uma página da Web poderia fazer de maneira diferente quando o dispositivo em que é renderizado é girado 270 graus, mas se você diz que possui um caso de uso válido, não vou reclamar. Nesse caso: desculpe, mas não faço ideia se o navegador Android fornece esse nível de detalhe.
Joel Mueller #
3

É possível em HTML5.
Você pode ler mais (e experimentar uma demonstração ao vivo) aqui: http://slides.html5rocks.com/#slide-orientation .

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

Ele também suporta navegadores de mesa, mas sempre retornará o mesmo valor.

Derek 朕 會 功夫
fonte
4
Este evento é realmente mais para acesso aos sensores de movimento, embora eu suponha que também possa ser usado para detectar alterações de orientação.
René
No meu Android Galaxy S2, ele não é suportado no navegador de ações nem no Navegador Dolphin. Mas funciona bem com o firefox móvel.
Eduardo
3

Eu tive o mesmo problema. Estou usando o Phonegap e o Jquery mobile, para dispositivos Adroid. Para redimensionar corretamente, tive que definir um tempo limite:

$(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
fonte
2

Aqui está a solução:

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
fonte
Esta é a solução que funcionou melhor para mim, sei que não é 100% precisa, mas você pode detectar horizontal e vertical usando isso: var screenWidth = $ (window) .width (); var screenHeight = $ (janela) .height (); if (screenWidth> screenHeight) {doSomething (); }
math0ne 4/09/15
Esta foi a solução para mim em um tablet Android de baixa qualidade. window.onresize, attachevent e addeventlistener falharam em vários eventos (redimensionar, redimensionar, mudança de orientação, orientação do dispositivo). Somente o Jquery $ (window) .on () funcionou.
Lego
1

Outra dica: alguns tablets Android (o Motorola Xoom que acredito e um Elonex de baixo custo que estou testando, provavelmente outros também) têm seus acelerômetros configurados para que window.orientation == 0 no modo PAISAGEM, não retrato !

james-geldart
fonte
1

você pode experimentar a solução, compatível com todos os navegadores.

A seguir, é apresentada uma orientationchangefoto de compatibilidade: compatibilidade portanto, eu orientaionchangeautorio um polyfill, que é baseado no atributo @media para corrigir a biblioteca de utilitários de positionchange—— orientedchange -fix

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

Vale ressaltar que, no Epic 4G Touch, tive que configurar a visualização na web para usar o WebChromeClient antes que qualquer uma das chamadas javascript no Android funcionasse.

webView.setWebChromeClient(new WebChromeClient());
calebisstupid
fonte
0

Caminho entre navegadores

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

Uma pequena contribuição para a resposta do idiota:

Conforme descrito na tabela em telefones droid, o evento "orientedchange" é acionado antes do evento "redimensionar", bloqueando a próxima chamada de redimensionamento (por causa da instrução if). A propriedade Width ainda não está definida.

Uma solução alternativa, embora talvez não perfeita, poderia ser a de não acionar o evento "mudança de orientação". Isso pode ser arquivado envolvendo a ligação de evento "guidancechange" na instrução "if":

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

Espero que ajude

(testes foram feitos no Nexus S)

Alex
fonte