Détecter la rotation du téléphone Android dans le navigateur avec JavaScript

190

Je sais que dans Safari sur un iPhone, vous pouvez détecter l'orientation de l'écran et le changement d'orientation en écoutant l' onorientationchangeévénement et en window.orientationrecherchant l'angle.

Est-ce possible dans le navigateur sur les téléphones Android?

Pour être clair, je demande si la rotation d'un appareil Android peut être détectée par JavaScript s'exécutant sur une page Web standard. C'est possible sur un iPhone, et je me suis demandé si cela pouvait être fait pour les téléphones Android.

Philnash
la source

Réponses:

214

Pour détecter un changement d'orientation sur un navigateur Android, associez un écouteur à l' événement orientationchangeou resizesur 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);

Vérifiez la window.orientationpropriété pour déterminer l'orientation de l'appareil. Avec les téléphones Android, screen.widthou screen.heightégalement des mises à jour lorsque l'appareil est tourné. (ce n'est pas le cas avec l'iPhone).

jb.
la source
ça marche vraiment? j'ai essayé jquery $ (window) .bind ("orientationchange", fn); mais cela n'a pas fonctionné, dois-je utiliser le formulaire ci-dessus? j'ai essayé "onorientationchange" dans la fenêtre, il revient faux
Ayyash
Ça marche bien. Ayyash - le point entier ici que lorsque "orientationchange" n'est pas pris en charge, il reviendra au "redimensionner"
Dror
9
Sur le droïde, c'est complètement fou. Il alerte screen.width de 320 lorsque le téléphone est tourné en mode paysage, et il détecte screen.width 569 lorsque le téléphone est tourné en mode portrait! Comment venir??
IgorGanapolsky le
1
Juste pour clarifier: ceux qui recherchent une solution qui fonctionne également sur iOS devraient regarder deux bits-fool's ou ma réponse.
mklement0
4
Pas besoin d'utiliser le hack de two-bit-fool pour iOS. Utilisez simplement screen.width et screen.height sur Android et sur iOS, utilisez window.innerWidth et window.innerHeight.
Justin
229

Le comportement réel sur les différents appareils est incohérent . Les événements resize et orientationChange peuvent se déclencher dans une séquence différente avec une fréquence variable. De plus, certaines valeurs (par exemple screen.width et window.orientation) ne changent pas toujours lorsque vous vous y attendez. Évitez screen.width - cela ne change pas lors de la rotation dans iOS.

L'approche fiable consiste à écouter à la fois les événements de redimensionnement et d'orientationChange (avec une interrogation comme prise de sécurité), et vous obtiendrez finalement une valeur valide pour l'orientation. Lors de mes tests, les appareils Android ne parviennent parfois pas à déclencher des événements lors d'une rotation complète de 180 degrés.J'ai donc également inclus un setInterval pour interroger l'orientation.

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

Voici les résultats des quatre appareils que j'ai testés (désolé pour le tableau ASCII, mais cela semblait être le moyen le plus simple de présenter les résultats). Mis à part la cohérence entre les appareils iOS, il existe une grande variété entre les appareils. REMARQUE: les événements sont répertoriés dans l'ordre de leur déclenchement.

| ================================================== ============================== |
| Appareil | Événements déclenchés | orientation | innerWidth | screen.width |
| ================================================== ============================== |
| iPad 2 | redimensionner | 0 | 1024 | 768 |
| (au paysage) | orientationchange | 90 | 1024 | 768 |
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
| iPad 2 | redimensionner | 90 | 768 | 768 |
| (au portrait) | orientationchange | 0 | 768 | 768 |
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
| iPhone 4 | redimensionner | 0 | 480 | 320 |
| (au paysage) | orientationchange | 90 | 480 | 320 |
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
| iPhone 4 | redimensionner | 90 | 320 | 320 |
| (au portrait) | orientationchange | 0 | 320 | 320 |
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
| Téléphone Droid | orientationchange | 90 | 320 | 320 |
| (au paysage) | redimensionner | 90 | 569 | 569 |
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
| Téléphone Droid | orientationchange | 0 | 569 | 569 |
| (au portrait) | redimensionner | 0 | 320 | 320 |
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
| Samsung Galaxy | orientationchange | 0 | 400 | 400 |
| Tablette | orientationchange | 90 | 400 | 400 |
| (au paysage) | orientationchange | 90 | 400 | 400 |
| | redimensionner | 90 | 683 | 683 |
| | orientationchange | 90 | 683 | 683 |
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
| Samsung Galaxy | orientationchange | 90 | 683 | 683 |
| Tablette | orientationchange | 0 | 683 | 683 |
| (au portrait) | orientationchange | 0 | 683 | 683 |
| | redimensionner | 0 | 400 | 400 |
| | orientationchange | 0 | 400 | 400 |
| ---------------- + ------------------- + ------------ - + ------------ + -------------- |
imbécile de deux bits
la source
Dans l'émulateur iOS5, si vous actualisez en mode paysage puis faites pivoter, ce code ne se déclenche pas.
travaillé
1
Très bonne réponse. previousOrientationdoit être initialisé avec l'orientation alors actuelle: var previousOrientation = window.orientation;Si vous voulez ignorer les rotations à 180 degrés, c'est-à-dire que vous n'avez pas besoin de faire la distinction entre le paysage gauche ou droit et les variantes inversées ou non, ajoutez comme première ligne pour checkOrientation(): if (0 === (previousOrientation + window.orientation) % 180) return;Cependant, sans setTimeoutastuce supplémentaire , vous n'en bénéficierez que sur iOS, où une rotation rapide à 180 degrés ne crée qu'un seul orientationchange événement.
mklement0
Merci @mklement, j'ai modifié le code pour initialiser la previousOrientation.
two-bit-fool
Vive les bonnes informations. Cela me faisait la tête parce que Windows Phone 8.1 ne comporte pas d'événement de redimensionnement ou de changement d'orientation lorsque vous utilisez cordova. Recours à l'utilisation de setInterval ainsi que de la sécurité intégrée.
Perfection
@ mklement0 À ce jour, window.orientation sera toujours indéfinie sur Windows Phone 8.1.
Perfection
41

L'excellente réponse de two-bit-fool fournit tout le contexte, mais laissez-moi tenter un résumé concis et pragmatique de la façon de gérer les changements d'orientation sur iOS et Android :

  • Si vous ne vous souciez que des dimensions de la fenêtre (le scénario typique) - et non de l'orientation spécifique:
    • Gérez l' resizeévénement uniquement.
    • Dans votre gestionnaire, agissez sur window.innerWidthet window.InnerHeightseulement.
    • NE PAS utiliser window.orientation- il ne sera pas à jour sur iOS.
  • Si vous vous souciez de l' orientation spécifique :
    • Gérez uniquement l' resizeévénement sur Android et uniquement l' orientationchangeévénement sur iOS.
    • Dans votre gestionnaire, agissez sur window.orientation(et window.innerWidthet window.InnerHeight)

Ces approches offrent de légers avantages par rapport à se souvenir de l'orientation précédente et à comparer:

  • L'approche basée uniquement sur les dimensions fonctionne également lors du développement sur des navigateurs de bureau qui peuvent autrement simuler des appareils mobiles, par exemple Chrome 23. ( window.orientationn'est pas disponible sur les navigateurs de bureau).
  • pas besoin d'une variable globale / anonyme au niveau du fichier de fonction.
mklement0
la source
Le problème est que lorsque l'événement de redimensionnement ou d'orientation déclenche le window.innerWidth signale des périphériques erronés et Droid
albanx
@albanx qui est toujours un problème dans Chrome sur iOS: / safari is fine tho
oldboy
12

Vous pouvez toujours écouter l'événement de redimensionnement de la fenêtre. Si, lors de cet événement, la fenêtre est passée de plus haute que large à plus large que haute (ou vice versa), vous pouvez être à peu près sûr que l'orientation du téléphone vient d'être modifiée.

Joel Mueller
la source
C'est une bonne idée, je vais essayer ça (et demander à mon ami avec le téléphone Android de tester!)
philnash
Je viens de réaliser que cette méthode ne me donne pas l'orientation du téléphone. Je saurai s'il s'agit d'un portrait ou d'un paysage, mais pas s'il est à l'envers ou a été tourné vers la gauche ou vers la droite. D'autres idées?
philnash
Je ne sais pas en quoi cela pourrait avoir une importance ... Pourquoi avez-vous besoin de savoir si le téléphone est à l'envers? Le navigateur du téléphone a un haut et la page Web sera orientée vers le haut du navigateur. Tout utilisateur avec deux cellules cérébrales à frotter qui regarde une page Web à l'envers va simplement retourner son téléphone s'il veut le voir
Joel Mueller
1
C'est un peu dur. Je suis intéressé de savoir pour que je puisse afficher différents contenus en fonction de l'orientation de l'écran, cela pourrait être jusqu'à 4 pages différentes, obligeant le navigateur à savoir s'il avait été tourné de 0, 90, 180 et 270 degrés. Tout cela est possible, en JavaScript, sur l'iPhone et c'est pourquoi je le demande.
philnash
J'ai toujours du mal à imaginer ce qu'une page Web pourrait utilement faire différemment lorsque l'appareil sur lequel elle est rendue est pivoté de 270 degrés, mais si vous dites que vous avez un cas d'utilisation valide, je ne vais pas chipoter. Dans ce cas: je suis désolé, mais je n'ai aucune idée si le navigateur Android fournit ce niveau de détail.
Joel Mueller
3

C'est possible en HTML5.
Vous pouvez en savoir plus (et essayer une démo en direct) ici: http://slides.html5rocks.com/#slide-orientation .

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

Il prend également en charge les navigateurs de bureau, mais il renvoie toujours la même valeur.

Derek 朕 會 功夫
la source
4
Cet événement est vraiment plus pour l'accès aux capteurs de mouvement, même si je suppose qu'il peut également être utilisé pour détecter un changement d'orientation.
René
Sur mon Android Galaxy S2, il n'est pas pris en charge sur le navigateur de stock ni sur le navigateur Dolphin. Mais fonctionne bien avec Firefox mobile.
Eduardo
3

J'ai eu le même problème. J'utilise Phonegap et Jquery mobile, pour les appareils Adroid. Pour redimensionner correctement, j'ai dû définir un délai d'attente:

$(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
la source
2

Voici la solution:

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
la source
C'est la solution qui a le mieux fonctionné pour moi, je sais qu'elle n'est pas précise à 100%, mais vous pouvez détecter l'horizontale par rapport à la verticale en utilisant ceci: var screenWidth = $ (window) .width (); var screenHeight = $ (fenêtre) .height (); if (screenWidth> screenHeight) {doSomething (); }
math0ne
Celui-ci était la solution pour moi sur une tablette Android de merde. window.onresize, attachevent et addeventlistener ont échoué sur plusieurs événements (redimensionnement, onresize, orientationchange, deviceorientation). Seul Jquery $ (window) .on () a fonctionné.
Lego
1

Un autre problème - certaines tablettes Android (le Motorola Xoom je crois et un Elonex bas de gamme sur lequel je fais des tests, probablement d'autres aussi) ont leurs accéléromètres configurés de sorte que window.orientation == 0 en mode LANDSCAPE, pas en mode portrait !

James-Geldart
la source
1

vous pouvez essayer la solution, compatible avec tous les navigateurs.

Voici la orientationchangephoto de compatibilité: par compatibilité conséquent, je orientaionchangecrée un polyfill, c'est un attribut basé sur @media pour corriger la bibliothèque de l'utilitaire orientationchange—— orientationchange-fix

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

Il convient de noter que sur mon Epic 4G Touch, j'ai dû configurer la vue Web pour utiliser WebChromeClient avant que les appels javascript Android ne fonctionnent.

webView.setWebChromeClient(new WebChromeClient());
calebisstupide
la source
0

Traverser le navigateur

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

Une petite contribution à la réponse du fou à deux bits:

Comme décrit sur le tableau sur les téléphones droïdes, l'événement "orientationchange" est déclenché plus tôt que l'événement "resize" bloquant ainsi le prochain appel de redimensionnement (à cause de l'instruction if). La propriété Width n'est toujours pas définie.

Une solution de contournement mais peut-être pas parfaite pourrait être de ne pas déclencher l'événement "orientationchange". Cela peut être archivé en encapsulant la liaison d'événement "orientationchange" dans l'instruction "if":

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

J'espère que cela aide

(les tests ont été effectués sur Nexus S)

Alex
la source