Как правильно определить изменение ориентации с помощью Phonegap на iOS?

178

Я нашел этот код теста ориентации ниже в поисках справочного материала JQTouch Это работает правильно в симуляторе iOS на мобильном Safari, но неправильно обрабатывается в Phonegap. Мой проект сталкивается с той же проблемой, которая убивает эту тестовую страницу. Есть ли способ почувствовать изменение ориентации с помощью JavaScript в 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;
  }
}
ajpalma
источник

Ответы:

297

Вот что я делаю:

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


Обновление от мая 2019 года: window.orientation устарела и не поддерживается большинством браузеров, согласно MDN . orientationchangeСобытие связано с window.orientation и , следовательно , должны , вероятно , не будет использоваться.

Бенни Нойгебауэр
источник
3
Это единственное решение, которое работает для меня из этого обсуждения :) +1
Атадж
9
Я сделалwindow.onorientationchange = function() { setTimeout(functionName, 0); };
Кирк Стробек
11
Из интереса, почему вы использовали setTimeout Kirk?
backdesk
10
Быть осторожен! Это зависит от устройства - градусы означают разницу со стандартной ориентацией устройства. Другими словами, если планшет предназначен для использования в альбомной ориентации, то 90 означает, что он находится в портретном режиме. Чтобы обойти это, я сначала проверяю высоту и ширину окна, чтобы сохранить ориентацию, и использую Ориентацию изменений, чтобы обновить ее, если есть изменения.
Беналлансмит
15
Кроме того, я обнаружил, что изменение ориентации срабатывает до изменения ширины и высоты, поэтому для правильного определения ориентации с использованием ширины и высоты требуется небольшая задержка. Для этого я сохраняю текущую ориентацию, и когда обнаруживается изменение, я проверяю изменение ориентации с шагом 50 мс до 250 мс. Как только разница обнаружена, я соответствующим образом обновляю страницу. На моем Nexus 5 он обычно определяет разницу ширины и высоты после 150 мс.
benallansmith
24

Я использую window.onresize = function(){ checkOrientation(); } И в checkOrientation вы можете использовать window.orientation или проверку ширины тела, но идея в том, что «window.onresize» является наиболее кросс-браузерным методом, по крайней мере, с большинством браузеров для мобильных и настольных компьютеров, которые у меня были. возможность проверить с.

hndcrftd
источник
1
Это отличный момент. Если вы разрабатываете с использованием веб-технологии, этот метод позволяет вам легче отлаживать и тестировать в браузере, а не развертывать / моделировать каждый раз.
Мэтт Рэй
2
Это совсем не нормально ... потому что когда появится клавиатура, она изменит свой размер (и это не единственный случай). Так что большое нет для этого!
HellBaby
2
@HellBaby Когда появится клавиатура, функция будет вызвана, однако, в зависимости от того, какой метод вы используете для определения ориентации, она обнаружит, что ориентация НЕ ИЗМЕНЕНА, как в случае с window.orientation. Поэтому я все еще поддерживаю мой ответ.
hndcrftd
1
@Raine Я использовал этот метод на Ipad 4 и был вынужден изменить его причину этой проблемы. Так что, возможно, это работает для некоторых устройств, но не для всех ..
HellBaby
1
@MattRay Вы можете легко протестировать изменения ориентации с помощью новейших инструментов разработчика, способных эмулировать такого рода поведение устройства.
Контур
14
if (window.matchMedia("(orientation: portrait)").matches) {
   // you're in PORTRAIT mode
}

if (window.matchMedia("(orientation: landscape)").matches) {
  // you're in LANDSCAPE mode
}
Алисса Рейес
источник
1
Вы можете прикрепить его к resizeсобытию. Тем не менее, IIRC, эти запросы не будут работать правильно с клавиатурой вверх.
adi518
12

Я довольно новичок в iOS и Phonegap, но я смог сделать это, добавив eventListener. Я сделал то же самое (используя пример, на который вы ссылаетесь), и не смог заставить его работать. Но это, казалось, добилось цели:

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

Возможно, вам повезет, когда вы поищите в Google Group PhoneGap термин «ориентация» .

Один пример, о котором я читал в качестве примера того, как определить ориентацию, был Pie Guy: ( игра , файл js ). Это похоже на код, который вы опубликовали, но, как и вы ... Я не смог заставить его работать.

Одно предостережение: eventListener работал для меня, но я не уверен, что это слишком интенсивный подход. До сих пор это был единственный способ, который работал для меня, но я не знаю, есть ли лучшие, более обтекаемые способы.


ОБНОВЛЕНИЕ исправил код выше, теперь работает

avoision
источник
пожалуйста, исправьте название события
Дан
5

При работе с orientationchangeсобытием мне понадобился тайм-аут, чтобы получить правильные размеры элементов на странице, но matchMedia работала нормально. Мой окончательный код:

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)
  });
}
oncode
источник
3

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

На некоторых платформах различные свойства, такие как размеры окна ( window.innerWidth, window.innerHeight) и window.orientationсвойство, не будут обновлены к моменту возникновения события "orientationchange". Много раз, свойство window.orientationэто в undefinedтечение нескольких миллисекунд после обжига "orientationchange"(по крайней мере, в Chrome на IOS).

Лучший способ найти решение этой проблемы:

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

Я проверяю, является ли ориентация либо неопределенной, либо ориентация равна последней обнаруженной ориентации. Если любое из этих значений истинно, я жду десять миллисекунд и затем снова анализирую ориентацию. Если ориентация правильная, я вызываю showXOrientationфункции. Если ориентация неверна, я продолжаю цикл проверки, ожидая десять миллисекунд каждый раз, пока она не станет действительной.

Теперь я бы сделал JSFiddle для этого, как обычно делал, но JSFiddle не работал для меня, и моя ошибка поддержки для него была закрыта, так как никто другой не сообщил об этой проблеме. Если кто-то еще хочет превратить это в JSFiddle, пожалуйста, продолжайте.

Спасибо! Надеюсь, это поможет!

WebWanderer
источник
К вашему сведению, при первоначальном тестировании я обнаружил проблему: я несколько раз поворачивался по часовой стрелке, и одно предупреждение показывало «Пейзажная ориентация: 180», хотя мое устройство было физически ориентировано как портрет.
MarsAndBack
2

вот что я сделал:

window.addEventListener('orientationchange', doOnOrientationChange);

function doOnOrientationChange()
{
      if (screen.height > screen.width) {
         console.log('portrait');
      } else {
         console.log('landscape');
      }
}
Рауль Гомес
источник
2

Хотя вопрос касается только использования PhoneGap и iOS, и хотя на него уже был дан ответ, я могу добавить несколько моментов к более широкому вопросу определения ориентации экрана с помощью JS в 2019 году:

  1. window.orientationсвойство устарело и не поддерживается браузерами Android. Существует более новое свойство, которое предоставляет больше информации об ориентации - screen.orientation. Но он все еще экспериментальный и не поддерживается iOS Safari . Таким образом , для достижения наилучшего результата вы , вероятно , нужно использовать комбинацию из двух: const angle = screen.orientation ? screen.orientation.angle : window.orientation.

  2. Как упомянул @benallansmith в своем комментарии , window.onorientationchangeсобытие вызывается раньше window.onresize, поэтому вы не получите фактические размеры экрана, если не добавите некоторую задержку после события directionalchange.

  3. Существует плагин Cordova Screen Orientation для поддержки старых мобильных браузеров, но я считаю, что в настоящее время его не нужно использовать.

  4. Также было screen.onorientationchangeсобытие, но оно устарело и не должно использоваться. Добавлено только для полноты ответа.

В моем случае использования я не заботился о фактической ориентации, а скорее о фактической ширине и высоте окна, которая, очевидно, меняется с ориентацией. Поэтому я использовал resizeсобытие, чтобы избежать задержек между orientationchangeсобытием и актуализацией размеров окна:

window.addEventListener('resize', () => {
  console.log(`Actual dimensions: ${window.innerWidth}x${window.innerHeight}`);
  console.log(`Actual orientation: ${screen.orientation ? screen.orientation.angle : window.orientation}`);
});

Примечание 1: здесь я использовал синтаксис EcmaScript 6, при необходимости обязательно скомпилируйте его в ES5.

Примечание 2: window.onresizeсобытие также вызывается при переключении виртуальной клавиатуры , а не только при изменении ориентации.

Алексей Гринько
источник
1

Я нашел этот код, чтобы определить, находится ли устройство в альбомной ориентации, и в этом случае добавить всплывающую страницу с надписью «изменить ориентацию, чтобы увидеть сайт». Работает на iOS, Android и Windows Phone. Я думаю, что это очень полезно, так как это довольно элегантно и избегать установки альбомной ориентации для мобильного сайта. Код работает очень хорошо. Единственное, что не совсем устраивает, это то, что если кто-то загружает страницу в альбомной ориентации, всплывающая страница не появляется.

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

И 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

У меня сработало следующее:

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

Мне нужно время ожидания, потому что значение window.orientationне обновляется сразу

catalyst294
источник
-3

Я создаю приложение jQTouch в PhoneGap для iPhone. Я боролся с этой проблемой в течение нескольких дней. Я видел предложенное решение Eventlistener несколько раз, но просто не смог заставить его работать.

В конце концов я придумал другое решение. Он в основном проверяет ширину тела периодически, используя settimeout. Если ширина равна 320, то ориентация книжная, если 480, то альбомная. Затем, если ориентация изменилась со времени последней проверки, она запустит либо функцию портретного заполнения, либо функцию ландшафтного заполнения, где вы можете выполнить свою задачу для каждой ориентации.

Код (заметьте, я знаю, что в коде есть некоторое повторение, но пока не удосужился его урезать!):

// 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
Жесткое кодирование устройства до 320 или 480 не будет работать в будущем или с нынешними телефонами высокого разрешения.
Fresheyeball
1
1) Вы должны использовать onresizeсобытие, которое сработает немедленно, а не через 500 миллисекунд. 2) Этот код специфичен для Android, используйте onorientationchangeвместо этого для iPhone 3) Проверьте, поддерживается ли он в браузере:"onorientationchange" in window
Dan