Como detecto corretamente as alterações de orientação usando o Phonegap no iOS?


178

Encontrei este código de teste de orientação abaixo procurando material de referência do JQTouch. Isso funciona corretamente no simulador iOS no Safari móvel, mas não é tratado corretamente no Phonegap. Meu projeto está executando o mesmo problema que está matando esta página de teste. Existe uma maneira de detectar a mudança de orientação usando JavaScript no 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;
  }
}

Respostas:


297

Isto é o que eu faço:

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


Atualização de maio de 2019: window.orientation é um recurso descontinuado e não é suportado pela maioria dos navegadores, de acordo com o MDN . O orientationchangeevento está associado ao window.orientation e, portanto, provavelmente não deve ser usado.


3
Essa é a única solução que funciona para mim nesta discussão :) +1
— Atadj

9
Eu fizwindow.onorientationchange = function() { setTimeout(functionName, 0); };
— Kirk Strobeck

11
Por interesse, por que você usou o setTimeout Kirk?
— backdesk

10
Seja cuidadoso! Isso é específico do dispositivo - os graus referem-se à diferença da orientação padrão do dispositivo. Em outras palavras, se o tablet foi projetado para ser usado na paisagem, 90 significa que está no modo retrato. Como uma solução alternativa para isso, eu inicialmente verifico a altura x largura da janela para armazenar a orientação, e uso o directionchange para atualizá-lo, se houver uma alteração.
— precisa saber é o seguinte

15
Além disso, descobri que a mudança de orientação é acionada antes que a largura e a altura sejam alteradas; portanto, é necessário um pouco de atraso para detectar a orientação corretamente usando a largura e a altura. Para isso, armazeno a orientação atual e, quando uma alteração é detectada, verifico a alteração na orientação em incrementos de 50ms até 250ms. Quando uma diferença é encontrada, atualizo a página de acordo. No meu Nexus 5, ele geralmente detecta a diferença entre largura e altura após 150ms.
— 22416 benallansmith

24

Eu uso o window.onresize = function(){ checkOrientation(); } E no checkOrientation, você pode empregar a verificação window.orientation ou a largura do corpo, mas a ideia é que "window.onresize" seja o método mais compatível com vários navegadores, pelo menos na maioria dos navegadores móveis e de mesa que eu já tive. oportunidade de testar.


1
Este é um ótimo ponto. Se você estiver desenvolvendo usando uma tecnologia voltada para a Web, esse método permitirá depurar e testar mais facilmente em um navegador, em vez de implantar / simular a cada vez.
— Matt Ray

2
Isso não está ok ... porque quando o teclado aparece, ele é redimensionado (e esse não é o único caso). Então, um grande não por isso!
— HellBaby

2
@HellBaby Quando o teclado aparecer, a função será chamada, dependendo do método usado para a detecção de orientação, ele detectará que a orientação NÃO FOI ALTERADA, como seria o caso da janela.orientação. Então, eu ainda mantenho minha resposta.
— precisa saber é o seguinte

1
@ Raine Eu usei esse método em um iPad 4 e fui forçado a mudar a causa desse problema. Então, talvez ele está trabalhando para alguns dispositivos, mas não para todos ..
— HellBaby

1
@MattRay Você pode testar facilmente as alterações de orientação com os kits de ferramentas de desenvolvimento mais recentes, capazes de emular esse tipo de comportamento do 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
Você pode anexá-lo a um resizeevento. No entanto, IIRC, essas consultas não funcionarão corretamente com o teclado para cima.
— Adi518

12

Sou muito novo no iOS e no Phonegap também, mas consegui fazer isso adicionando um eventListener. Fiz a mesma coisa (usando o exemplo que você menciona) e não consegui fazê-lo funcionar. Mas isso parecia fazer o truque:

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

Você pode ter alguma sorte pesquisando no Grupo PhoneGap do Google o termo "orientação" .

Um exemplo que li sobre como detectar orientação foi Pie Guy: ( jogo , arquivo js ). É semelhante ao código que você postou, mas como você ... Eu não consegui fazê-lo funcionar.

Uma ressalva: o eventListener funcionou para mim, mas não tenho certeza se essa é uma abordagem excessivamente intensiva. Até agora, essa foi a única maneira que funcionou para mim, mas não sei se existem maneiras melhores e mais simplificadas.


UPDATE corrigiu o código acima, ele funciona agora


plese corrigir o nome do evento
— Dan

5

Enquanto trabalhava com o orientationchangeevento, precisava de um tempo limite para obter as dimensões corretas dos elementos na página, mas o matchMedia funcionou bem. Meu código 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)
  });
}

3

Acredito que a resposta correta já foi postada e aceita, mas há um problema que eu já experimentei e que alguns outros mencionaram aqui.

Em certas plataformas, várias propriedades, como as dimensões da janela ( window.innerWidth, window.innerHeight) e a window.orientationpropriedade, não serão atualizadas quando o evento "orientationchange"for disparado. Muitas vezes, a propriedade window.orientationfica undefinedpor alguns milissegundos após o disparo "orientationchange"(pelo menos no Chrome no iOS).

A melhor maneira que encontrei para lidar com esse problema foi:

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

Estou verificando se a orientação é indefinida ou se a orientação é igual à última orientação detectada. Se qualquer um for verdadeiro, espero dez milissegundos e analiso a orientação novamente. Se a orientação for um valor adequado, chamo as showXOrientationfunções. Se a orientação for inválida, continuo repetindo minha função de verificação, aguardando dez milissegundos por vez, até que seja válida.

Agora, eu faria um JSFiddle para isso, como costumava fazer, mas o JSFiddle não está funcionando para mim e meu bug de suporte foi fechado, pois ninguém mais está relatando o mesmo problema. Se alguém quiser transformar isso em um JSFiddle, vá em frente.

Obrigado! Eu espero que isso ajude!


Para sua informação, nos testes iniciais, vi um problema: giro no sentido horário algumas vezes e um alerta dizia "Paisagem Orientação: 180", mesmo que meu dispositivo estivesse fisicamente orientado como retrato.
— MarsAndBack

2

aqui está o que eu fiz:

window.addEventListener('orientationchange', doOnOrientationChange);

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

2

Embora a pergunta se refira apenas ao uso do PhoneGap e iOS, e embora já tenha sido respondida, posso acrescentar alguns pontos à questão mais ampla de detectar a orientação da tela com JS em 2019:

  1. window.orientationpropriedade é obsoleto e não suportado por navegadores Android .Não é um hotel novo que fornece mais informações sobre a orientação - screen.orientation. Mas ainda é experimental e não é suportado pelo iOS Safari . Assim, para obter o melhor resultado, você provavelmente precisará usar a combinação dos dois: const angle = screen.orientation ? screen.orientation.angle : window.orientation.

  2. Como @benallansmith mencionou em seu comentário , o window.onorientationchangeevento é disparado antes window.onresize, portanto, você não obterá as dimensões reais da tela, a menos que adicione algum atraso após o evento de mudança de orientação.

  3. Existe um plug-in de orientação de tela Cordova para oferecer suporte a navegadores móveis mais antigos, mas acredito que não há necessidade de usá-lo atualmente.

  4. Houve também um screen.onorientationchangeevento, mas está obsoleto e não deve ser usado. Adicionado apenas para completar a resposta.

No meu caso de uso, não me importei muito com a orientação real, mas com a largura e altura reais da janela, o que obviamente muda com a orientação. Então, usei resizeevent para evitar lidar com atrasos entre as orientationchangedimensões do evento e a atualização da janela:

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: Usei a sintaxe do EcmaScript 6 aqui, certifique-se de compilá-la no ES5, se necessário.

Nota 2: o window.onresizeevento também é acionado quando o teclado virtual é alternado , não apenas quando a orientação é alterada.


1

Encontrei este código para detectar se o dispositivo está na orientação paisagem e, neste caso, adicione uma página inicial dizendo "alterar orientação para ver o site". Está funcionando nos telefones iOS, Android e Windows. Eu acho que isso é muito útil, pois é bastante elegante e evita definir uma paisagem para o site para celular. O código está funcionando muito bem. A única coisa que não é totalmente satisfatória é que, se alguém carregar a página em modo paisagem, a página inicial não aparecerá.

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

O seguinte funcionou para mim:

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

Eu precisava do tempo limite porque o valor de window.orientationnão é atualizado imediatamente


-3

Estou criando um aplicativo jQTouch no PhoneGap para o iPhone. Estou lutando com esse problema há dias. Vi a solução eventlistener sugerida algumas vezes, mas não consegui fazê-la funcionar.

No final, eu vim com uma solução diferente. Basicamente, verifica a largura do corpo periodicamente usando settimeout. Se a largura for 320, a orientação é retrato; se 480, é paisagem. Então, se a orientação tiver sido alterada desde a última verificação, ela disparará uma função de material de retrato ou de paisagem, onde você poderá fazer o que quiser para cada orientação.

Código (note, eu sei que há alguma repetição no código, mas não se preocupe em reduzi-lo ainda!):

// 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
A codificação embutida do dispositivo para 320 ou 480 não funcionará no futuro ou com os telefones de alta resolução atuais.
— Fresheyeball 18/10/11

1
1) Você deve usar um onresizeevento que será acionado imediatamente, não em 500 milissegundos 2) Este código é específico para o Android, use onorientationchangepara o iPhone 3) Teste se é suportado no navegador:"onorientationchange" in window
— Dan
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.