Высота мобильного просмотра после изменения ориентации

Я присоединяю слушателя к событию orientationchange:

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

Мне нужно получить высоту документа после orientationchange. Однако событие запускается до завершения вращения. Поэтому записанная высота отражает состояние до фактического изменения ориентации.

Как зарегистрировать событие, которое позволит мне фиксировать размеры элемента после завершения изменения ориентации?

Ответ 1

Для изменения ориентации требуется задержка для получения новых высот и ширины. Это работает в 80% случаев.

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

Ответ 2

Используйте событие изменения размера

Событие изменения размера будет включать соответствующую ширину и высоту после изменения ориентации, но вы не хотите слушать все события изменения размера. Поэтому мы добавляем одноразовый прослушиватель событий изменения размера после изменения ориентации:

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

НЕ используйте таймауты

Тайм-ауты ненадежны - некоторые устройства не смогут зафиксировать свое изменение ориентации в своих жестко запрограммированных таймаутах; это может быть по непредвиденным причинам или потому, что устройство работает медленно. Быстрые устройства будут обратно запрограммировать ненужную задержку в коде.

Ответ 3

Решения Gajus и burtelli надежны, но накладные расходы высоки. Вот небольшая версия, которая достаточно быстро работает в 2017 году, используя 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);
  });
}

Используйте его следующим образом:

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

Ответ 4

Невозможно зафиксировать конец события изменения ориентации, поскольку обработка изменения ориентации зависит от браузера и браузера. Нанесение баланса между самым надежным и быстрым способом обнаружения конца изменения ориентации требует гоночного интервала и таймаута.

Слушатель подключен к orientationchange. Вызов слушателя начинает интервал. Интервал отслеживает состояние window.innerWidth и window.innerHeight. Событие orientationchangeend запускается, когда noChangeCountToEnd число последующих итераций не обнаруживает мутации значения или после noEndTimeout миллисекунд, в зависимости от того, что произойдет раньше.

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

Я поддерживаю реализацию orientationchangeend, которая распространяется на вышеописанную логику.

Ответ 5

Я использовал обходное решение, предложенное Гаюсом Куйзунасом, какое-то время, которое было надежным, хотя и немного медленным. Спасибо, во всяком случае, это сработало!

Если вы используете Cordova или Phonegap, я нашел более быстрое решение - на случай, если кто-то еще столкнется с этой проблемой в будущем. Этот плагин сразу возвращает правильные значения ширины/высоты: https://github.com/pbakondy/cordova-plugin-screensize

Возвращенная высота и ширина отражают фактическое разрешение, поэтому, возможно, вам придется использовать window.devicePixelRatio для получения пикселей в видовом экране. Также строка заголовка (батарея, время и т.д.) Включена в возвращаемую высоту. Я использовал эту функцию обратного вызова initally (onDeviceReady)

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

В вашем обработчике событий изменения ориентации вы можете использовать:

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

чтобы сразу получить innerHeight. Надеюсь, это поможет кому-то!

Ответ 6

Я также столкнулся с той же проблемой. Поэтому я закончил использование:

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

Ответ 7

Это экспериментальная функция, которая дает правильные innerHeight и innerWidth после изменения ориентации экрана.

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

Я думаю, что прослушивание изменения размера окна - это самый безопасный способ реализовать логику изменения ориентации экрана.

Ответ 8

Важно отметить, что ориентация не будет получать высоту после изменения, а скорее до. Используйте для этого изменение размера.

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

Ответ 9

Я решил эту проблему, объединив пару вышеупомянутых решений. Изменение размера будет срабатывать 4-5 раз. Используя .one, он выстрелил слишком рано. Небольшое время, добавленное к решению Кристофера Булла, помогло.

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

Ответ 10

Для людей, которые просто хотят innerHeight объекта окна после orientationchange есть простое решение. Используйте window.innerWidth. innerWidth во время orientationchange мероприятия является innerHeight после завершения orientationchange:

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

Я не уверен, что изменения в 180 градусов выполняются в два этапа 90 градусов или нет. Невозможно имитировать это в браузере с помощью инструментов разработчика. Но если вы хотите защитить от полной возможности вращения на 180, 270 или 360, можно использовать screen.orientation.angle для вычисления угла и использования правильной высоты и ширины. screen.orientation.angle во время события является целевым углом orientationchange события.