web-dev-qa-db-fra.com

Hauteur de la fenêtre mobile après changement d'orientation

J'attache un écouteur à l'événement orientationchange :

window.addEventListener('orientationchange', function () {
    console.log(window.innerHeight);
});

J'ai besoin d'obtenir la hauteur du document après le orientationchange. Cependant, l'événement est déclenché avant la fin de la rotation. Par conséquent, la hauteur enregistrée reflète l'état avant le changement d'orientation réel.

Comment enregistrer un événement qui me permettrait de capturer les dimensions des éléments une fois le changement d'orientation terminé?

34
Dan Kanze

Le changement d'orientation a besoin d'un délai pour prendre en compte les nouvelles hauteurs et largeurs. Cela fonctionne 80% du temps.

window.setTimeout(function() {
    //insert logic with height or width calulations here.
}, 200);
9
Dan Kanze

tilisez l'événement resize

L'événement resize inclura la largeur et la hauteur appropriées après un orientationchange, mais vous ne voulez pas écouter tous les événements de redimensionnement. Par conséquent, nous ajoutons un écouteur d'événement de redimensionnement unique après un changement d'orientation:

Javascript :

window.addEventListener('orientationchange', function() {
    // After orientationchange, add a one-time resize event
    var afterOrientationChange = function() {
        // YOUR POST-ORIENTATION CODE HERE
        // Remove the resize event listener after it has executed
        window.removeEventListener('resize', afterOrientationChange);
    };
    window.addEventListener('resize', afterOrientationChange);
});

jQuery :

$(window).on('orientationchange', function() {
    // After orientationchange, add a one-time resize event
    $(window).one('resize', function() {
        // YOUR POST-ORIENTATION CODE HERE
    });
});

N'utilisez PAS de timeouts

Les délais d'attente ne sont pas fiables - certains appareils ne parviendront pas à capturer leur changement d'orientation dans vos délais d'attente codés en dur; cela peut être pour des raisons imprévues ou parce que l'appareil est lent. Les appareils rapides auront inversement un retard inutile dans le code.

25
Christopher Bull

Les solutions de Gajus et burtelli sont robustes mais les frais généraux sont élevés. Voici une version slim assez rapide en 2017, utilisant requestAnimationFrame:

// Wait until innerheight changes, for max 120 frames
function orientationChanged() {
  const timeout = 120;
  return new window.Promise(function(resolve) {
    const go = (i, height0) => {
      window.innerHeight != height0 || i >= timeout ?
        resolve() :
        window.requestAnimationFrame(() => go(i + 1, height0));
    };
    go(0, window.innerHeight);
  });
}

Utilisez-le comme ceci:

window.addEventListener('orientationchange', function () {
    orientationChanged().then(function() {
      // Profit
    });
});
16
kizzx2

Il n'y a aucun moyen de capturer la fin de l'événement de changement d'orientation car la gestion du changement d'orientation varie d'un navigateur à l'autre. Tracer un équilibre entre le moyen le plus fiable et le plus rapide pour détecter la fin du changement d'orientation nécessite un intervalle de course et un délai d'attente.

Un écouteur est attaché au orientationchange. L'appel de l'écouteur démarre un intervalle. L'intervalle suit l'état de window.innerWidth et window.innerHeight. L'événement orientationchangeend est déclenché lorsque noChangeCountToEnd nombre d'itérations consécutives ne détecte pas de mutation de valeur ou après noEndTimeout millisecondes, selon la première éventualité.

var noChangeCountToEnd = 100,
    noEndTimeout = 1000;

window
    .addEventListener('orientationchange', function () {
        var interval,
            timeout,
            end,
            lastInnerWidth,
            lastInnerHeight,
            noChangeCount;

        end = function () {
            clearInterval(interval);
            clearTimeout(timeout);

            interval = null;
            timeout = null;

            // "orientationchangeend"
        };

        interval = setInterval(function () {
            if (global.innerWidth === lastInnerWidth && global.innerHeight === lastInnerHeight) {
                noChangeCount++;

                if (noChangeCount === noChangeCountToEnd) {
                    // The interval resolved the issue first.

                    end();
                }
            } else {
                lastInnerWidth = global.innerWidth;
                lastInnerHeight = global.innerHeight;
                noChangeCount = 0;
            }
        });
        timeout = setTimeout(function () {
            // The timeout happened first.

            end();
        }, noEndTimeout);
    });

Je maintiens une implémentation de orientationchangeend qui s'étend sur la logique décrite ci-dessus.

14
Gajus

J'ai utilisé la solution de contournement proposée par Gajus Kuizunas pendant un certain temps, ce qui était fiable mais un peu lent. Merci quand même, ça a fait le boulot!

Si vous utilisez Cordova ou Phonegap, j'ai trouvé une solution plus rapide - juste au cas où quelqu'un d'autre serait confronté à ce problème à l'avenir. Ce plugin renvoie immédiatement les valeurs de largeur/hauteur correctes: https://github.com/pbakondy/cordova-plugin-screensize

La hauteur et la largeur renvoyées reflètent cependant la résolution réelle, vous devrez donc peut-être utiliser window.devicePixelRatio pour obtenir les pixels de la fenêtre. La barre de titre (batterie, temps, etc.) est également incluse dans la hauteur renvoyée. J'ai utilisé cette fonction de rappel au départ (onDeviceReady)

var successCallback = function(result){
    var ratio = window.devicePixelRatio;            
    settings.titleBar = result.height/ratio-window.innerHeight; 
    console.log("NEW TITLE BAR HEIGHT: " + settings.titleBar);
};

Dans votre gestionnaire d'événements de changement d'orientation, vous pouvez ensuite utiliser:

height = result.height/ratio - settings.titleBar;

pour obtenir la hauteur intérieure tout de suite. J'espère que cela aide quelqu'un!

2
burtelli

J'ai résolu ce problème en combinant quelques-unes des solutions ci-dessus. Le redimensionnement se déclencherait 4 à 5 fois. En utilisant .one, il a tiré trop tôt. Un court délai ajouté à la solution de Christopher Bull a fait l'affaire.

$(window).on('orientationchange', function () {
  $(window).one('resize', function () {
    setTimeout(reference_to_function, 100);
  });
});
1
Meursault

J'ai également rencontré le même problème. J'ai donc fini par utiliser:

window.onresize = function(){ getHeight(); }
1
Coisox

Il s'agit d'une fonctionnalité expérimentale qui donne la bonne innerHeight et innerWidth une fois l'orientation de l'écran modifiée.

window.screen.orientation.addEventListener('change', function(){
    console.log(window.innerHeight)
})

Je pense que l'écoute du redimensionnement de la fenêtre est le moyen le plus sûr de mettre en œuvre une logique de changement d'orientation d'écran.

1
sudazzle

Il est important de noter que le changement d'orientation n'obtiendra pas la hauteur après le changement, mais plutôt avant. Utilisez redimensionner pour y parvenir.

$(window).bind('orientationchange', function (e) {
    var windowHeight = $(window).innerHeight();
    console.log('Before Orientation: Height = ' + windowHeight);

    $(window).resize(function () {
        windowHeight = $(window).innerHeight();
        console.log('After Orientation: Height = ' + windowHeight);
    });
});
1
Kevin

Pour les personnes qui souhaitent simplement le innerHeight de l'objet fenêtre après le orientationchange, il existe une solution simple. Utilisation window.innerWidth. innerWidth pendant l'événement orientationchange est le innerHeight après la fin de orientationchange:

window.addEventListener('orientationchange', function () {
    var innerHeightAfterEvent = window.innerWidth;
    console.log(innerHeightAfterEvent);
    var innerWidthAfterEvent = window.innerHeight;
    console.log(innerWidthAfterEvent);
    console.log(screen.orientation.angle);
});

Je ne sais pas si les changements à 180 degrés sont effectués en deux étapes à 90 degrés ou non. Impossible de simuler cela dans le navigateur à l'aide d'outils de développement. Mais si vous souhaitez vous protéger contre une possibilité de rotation complète de 180, 270 ou 360, il devrait être possible d'utiliser screen.orientation.angle pour calculer l'angle et utiliser la hauteur et la largeur correctes. Le screen.orientation.angle pendant l'événement est l'angle cible de l'événement orientationchange.

0
coderuby