Як правильно визначити зміну орієнтації за допомогою 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;
  }
}

Відповіді:


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?
бекдек

10
Будь обережний! Це специфічно для пристрою - градуси відносяться до відмінності від стандартної орієнтації пристроїв. Іншими словами, якщо планшет призначений для використання в ландшафті, то 90 означатиме, що він знаходиться в портретному режимі. Як вирішення цього питання, я спочатку перевіряю висоту та ширину вікна, щоб зберігати орієнтацію, і використовую орієнтацію зміни, щоб оновити це, якщо є зміни.
benallansmith

15
Крім того, я виявив, що зміна орієнтації спрацьовує перед зміною ширини та висоти, тому потрібна невелика затримка, щоб правильно визначити орієнтацію за допомогою ширини та висоти. Для цього я зберігаю поточну орієнтацію, і коли виявляється зміна, я перевіряю на зміну орієнтації з кроком 50 мс до 250 мс. Як тільки буде знайдена різниця, я оновлюю відповідну сторінку відповідно. На моєму Nexus 5 він зазвичай визначає різницю ширини та висоти через 150 мс.
benallansmith

24

Я використовую window.onresize = function(){ checkOrientation(); } І в checkOrientation ви можете використовувати window.orientation або перевірку ширини тіла, але ідея полягає в тому, що "window.onresize" є самим перехресним методом браузера, принаймні для більшості мобільних і настільних браузерів, у яких був можливість спробувати.


1
Це чудовий момент. Якщо ви розробляєте технологію, яка працює на веб-сторінках, цей метод дозволяє налагоджувати і тестувати простіше у браузері, а не щоразу розгортати / моделювати.
Метт Рей

2
Це зовсім не нормально ... тому що, коли з'явиться клавіатура, вона змінить розмір (і це не єдиний випадок). Тож великий ні для цього!
HellBaby

2
@HellBaby Коли з'явиться клавіатура, функція буде викликана, однак, залежно від того, який метод ви використовуєте для виявлення орієнтації, вона виявить, що орієнтація НЕ ЗМІНЕНА, як у випадку з window.orientation. Тому я все ще стою свою відповідь.
hndcrftd

1
@Raine Я використовував цей метод на Ipad 4 і був змушений змінити його причину цієї проблеми. Тож, можливо, він працює для деяких пристроїв, але не для всіх ..
HellBaby

1
@MattRay Ви можете легко перевірити зміни орієнтації за допомогою останніх наборів інструментів для розробників, здатних імітувати подібну поведінку пристрою.
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
Ви можете долучити його до 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 PhoneGap термін "орієнтація" .

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

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


UPDATE виправив код вище, він працює зараз


ласка, зафіксуйте назву події
День

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

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, будь ласка, вперед.

Дякую! Я сподіваюся, що це допомагає!


FYI, на первинному тестуванні я побачив проблему: я кілька разів обертався за годинниковою стрілкою, і одне попередження сказало "Пейзажна орієнтація: 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, тому фактичні розміри екрана ви не отримаєте, якщо ви не додасте деякої затримки після події зміни орієнтації.

  3. Існує плагін для орієнтації на екрани Cordova для підтримки старих мобільних браузерів, але я вважаю, що зараз немає необхідності використовувати його.

  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. Я думаю, що це дуже корисно, оскільки це досить елегантно і уникати встановлення пейзажного виду для мобільного сайту. Код працює дуже добре. Єдине, що не повністю задовольняє, це те, що якщо хтось завантажує сторінку, що знаходиться в альбомному вигляді, сторінка сплеску не з’являється.

<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не оновлюється відразу


-3

Я створюю додаток jQTouch у PhoneGap для iPhone. Я боровся з цим питанням цілими днями. Я бачив рішення, яке пропонувало eventlistener кілька разів, але просто не зміг його працювати.

Врешті-решт я придумав інше рішення. В основному він періодично перевіряє ширину тіла, використовуючи встановлений час. Якщо ширина 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
День
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.