Jak poprawnie wykryć zmianę orientacji za pomocą Phonegap na iOS?

178

Znalazłem ten kod testu orientacji poniżej, szukając materiału referencyjnego JQTouch. Działa to poprawnie w symulatorze iOS w mobilnym Safari, ale nie jest obsługiwane poprawnie w Phonegap. Mój projekt napotyka ten sam problem, który zabija tę stronę testową. Czy istnieje sposób na wyczucie zmiany orientacji za pomocą JavaScript w 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
źródło

Odpowiedzi:

297

Tym się właśnie zajmuję:

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


Aktualizacja z maja 2019 r .: window.orientation jest przestarzałą funkcją i według MDN nie jest obsługiwana przez większość przeglądarek . orientationchangeZdarzenie jest związane z window.orientation i dlatego nie powinna być używana.

Benny Neugebauer
źródło
3
To jedyne rozwiązanie, które działa dla mnie z tej dyskusji :) +1
Atadj
9
Zrobiłemwindow.onorientationchange = function() { setTimeout(functionName, 0); };
Kirk Strobeck
11
Z ciekawości, dlaczego użyłeś setTimeout Kirk?
backdesk
10
Bądź ostrożny! Jest to specyficzne dla urządzenia - stopnie odnoszą się do różnicy w stosunku do standardowej orientacji urządzenia. Innymi słowy, jeśli tablet jest przeznaczony do użytku w orientacji poziomej, 90 oznaczałoby, że jest w trybie pionowym. Aby obejść ten problem, początkowo sprawdzam wysokość i szerokość okna, aby zapisać orientację, i używam zmiany orientacji, aby zaktualizować to, jeśli nastąpi zmiana.
benallansmith
15
Dodatkowo odkryłem, że zmiana orientacji następuje przed zmianą szerokości i wysokości, dlatego potrzebne jest trochę opóźnienia, aby poprawnie wykryć orientację przy użyciu szerokości i wysokości. W tym celu przechowuję aktualną orientację, a po wykryciu zmiany sprawdzam zmianę orientacji w odstępach co 50 ms do 250 ms. Po znalezieniu różnicy odpowiednio aktualizuję stronę.Na moim Nexusie 5 zwykle wykrywa różnicę szerokości i wysokości po 150 ms.
benallansmith
24

Używam window.onresize = function(){ checkOrientation(); } I w checkOrientation możesz zastosować sprawdzanie window.orientation lub szerokości ciała, ale pomysł jest taki, że "window.onresize" jest metodą najbardziej korzystającą z przeglądarek, przynajmniej w przypadku większości przeglądarek mobilnych i stacjonarnych, które miałem możliwość przetestowania.

hndcrftd
źródło
1
To świetna uwaga. Jeśli programujesz przy użyciu technologii internetowej, ta metoda umożliwia łatwiejsze debugowanie i testowanie w przeglądarce zamiast wdrażania / symulacji za każdym razem.
Matt Ray,
2
To wcale nie jest w porządku ... ponieważ kiedy pojawi się klawiatura, zmieni rozmiar (i nie jest to jedyny przypadek). Więc wielkie nie za to!
HellBaby,
2
@HellBaby Gdy pojawi się klawiatura, funkcja zostanie wywołana, jednak w zależności od metody używanej do wykrywania orientacji wykryje, że orientacja NIE ZMIENIŁA SIĘ, tak jak w przypadku window.orientation. Więc nadal trzymam się swojej odpowiedzi.
hndcrftd
1
@Raine Użyłem tej metody na iPadzie 4 i byłem zmuszony zmienić ją z powodu tego problemu. Więc może to działa na niektórych urządzeniach, ale nie na wszystkich ...
HellBaby,
1
@MattRay Możesz łatwo testować zmiany orientacji za pomocą najnowszych zestawów narzędzi dla programistów, które są w stanie emulować tego rodzaju zachowanie urządzenia.
kontur
14
if (window.matchMedia("(orientation: portrait)").matches) {
   // you're in PORTRAIT mode
}

if (window.matchMedia("(orientation: landscape)").matches) {
  // you're in LANDSCAPE mode
}
Alyssa Reyes
źródło
1
Możesz dołączyć go do resizewydarzenia. Jednak IIRC, te zapytania nie będą działać poprawnie przy podniesionej klawiaturze.
adi518
12

Jestem całkiem nowy w iOS i Phonegap, ale udało mi się to zrobić, dodając eventListener. Zrobiłem to samo (używając przykładu, do którego się odnosisz) i nie mogłem go uruchomić. Ale to zdawało się działać:

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

Możesz mieć trochę szczęścia, wyszukując w grupie PhoneGap Google termin „orientacja” .

Jednym z przykładów, o którym czytałem jako przykład wykrywania orientacji, był Pie Guy: ( gra , plik js ). Jest podobny do kodu, który opublikowałeś, ale tak jak Ty ... Nie mogłem go uruchomić.

Jedno zastrzeżenie: eventListener zadziałał dla mnie, ale nie jestem pewien, czy jest to zbyt intensywne podejście. Jak dotąd był to jedyny sposób, który działał dla mnie, ale nie wiem, czy są lepsze, bardziej usprawnione sposoby.


UPDATE naprawił powyższy kod, teraz działa

unikanie
źródło
proszę poprawić nazwę wydarzenia
Dan
5

Podczas pracy z orientationchangewydarzeniem potrzebowałem limitu czasu, aby uzyskać prawidłowe wymiary elementów na stronie, ale matchMedia działało dobrze. Mój ostateczny kod:

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
źródło
3

Uważam, że poprawna odpowiedź została już opublikowana i zaakceptowana, ale jest problem, którego sam doświadczyłem i o którym wspominali tutaj inni.

Na niektórych platformach różne właściwości, takie jak wymiary okna ( window.innerWidth, window.innerHeight) i window.orientationwłaściwość nie zostaną zaktualizowane do czasu uruchomienia zdarzenia "orientationchange". Wielokrotnie nieruchomość window.orientationutrzymuje się undefinedprzez kilka milisekund po wypaleniu"orientationchange" (przynajmniej w Chrome na iOS).

Najlepszym sposobem rozwiązania tego problemu było:

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

Sprawdzam, czy orientacja jest niezdefiniowana lub czy orientacja jest równa ostatniej wykrytej orientacji. Jeśli jedno jest prawdą, czekam dziesięć milisekund, a następnie ponownie analizuję orientację. Jeśli orientacja jest właściwą wartością, nazywamshowXOrientation funkcje. Jeśli orientacja jest nieprawidłowa, kontynuuję pętlę funkcji sprawdzającej, za każdym razem czekając dziesięć milisekund, aż będzie ona prawidłowa.

Teraz zrobiłbym do tego JSFiddle, jak zwykle, ale JSFiddle nie działa dla mnie, a mój błąd wsparcia został zamknięty, ponieważ nikt inny nie zgłasza tego samego problemu. Jeśli ktoś jeszcze chce zamienić to w JSFiddle, proszę bardzo.

Dzięki! Mam nadzieję, że to pomoże!

WebWanderer
źródło
Do Twojej wiadomości, podczas wstępnych testów zauważyłem problem: obracałem się kilka razy zgodnie z ruchem wskazówek zegara i jeden z ostrzeżeń powiedział: „Orientacja pozioma: 180”, mimo że moje urządzenie było fizycznie ustawione jako portret.
MarsAndBack
2

oto co zrobiłem:

window.addEventListener('orientationchange', doOnOrientationChange);

function doOnOrientationChange()
{
      if (screen.height > screen.width) {
         console.log('portrait');
      } else {
         console.log('landscape');
      }
}
Raul Gomez
źródło
2

Chociaż pytanie dotyczy tylko wykorzystania PhoneGap i iOS i chociaż już na nie odpowiedziano, do szerszej kwestii wykrywania orientacji ekranu za pomocą JS w 2019 roku mogę dodać kilka punktów:

  1. window.orientationWłaściwość jest przestarzała i nie jest obsługiwana przez przeglądarki z systemem Android.Istnieje nowsza właściwość, która zawiera więcej informacji o orientacji - screen.orientation. Ale nadal jest eksperymentalny i nie jest obsługiwany przez iOS Safari . Tak, aby osiągnąć najlepszy wynik prawdopodobnie trzeba użyć kombinacji dwóch: const angle = screen.orientation ? screen.orientation.angle : window.orientation.

  2. Jak @benallansmith wspomniał w swoim komentarzu , window.onorientationchangezdarzenie jest uruchamiane wcześniej window.onresize, więc nie otrzymasz rzeczywistych wymiarów ekranu, chyba że dodasz opóźnienie po zdarzeniu zmiany orientacji.

  3. Istnieje wtyczka Cordova Screen Orientation do obsługi starszych przeglądarek mobilnych, ale uważam, że obecnie nie ma potrzeby jej używać.

  4. Wystąpiło również screen.onorientationchangezdarzenie, ale jest ono przestarzałe i nie powinno być używane. Dodano tylko dla kompletności odpowiedzi.

W moim przypadku nie przejmowałem się zbytnio rzeczywistą orientacją, ale raczej rzeczywistą szerokością i wysokością okna, która oczywiście zmienia się wraz z orientacją. Użyłem więc resizezdarzenia, aby uniknąć opóźnień między orientationchangezdarzeniem a aktualizacją wymiarów okna:

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

Uwaga 1: Użyłem tutaj składni EcmaScript 6, w razie potrzeby skompiluj ją do ES5.

Uwaga 2: window.onresizezdarzenie jest wyzwalane również przy przełączaniu klawiatury wirtualnej , a nie tylko przy zmianie orientacji.

Alexey Grinko
źródło
1

Znalazłem ten kod, aby wykryć, czy urządzenie jest w orientacji poziomej iw tym przypadku dodaj stronę powitalną z napisem „Zmień orientację, aby zobaczyć witrynę”. Działa na telefonach z systemem iOS, Android i Windows. Myślę, że jest to bardzo przydatne, ponieważ jest dość eleganckie i nie należy ustawiać widoku poziomego dla witryny mobilnej. Kod działa bardzo dobrze. Jedyną rzeczą nie do końca satysfakcjonującą jest to, że jeśli ktoś załaduje stronę w widoku poziomym, strona powitalna nie pojawi się.

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

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

Luigi
źródło
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
    }
}
M Fauzi Riozi
źródło
-2

Pracowały dla mnie:

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

Potrzebowałem limitu czasu, ponieważ wartość window.orientationnie aktualizuje się od razu

katalizator294
źródło
-3

Tworzę aplikację jQTouch w PhoneGap na iPhone'a. Walczę z tym problemem od dni. Kilka razy widziałem sugerowane rozwiązanie Eventlistener, ale po prostu nie udało mi się go uruchomić.

W końcu wpadłem na inne rozwiązanie. Zasadniczo sprawdza okresowo szerokość korpusu za pomocą settimeout. Jeśli szerokość wynosi 320, orientacja jest pionowa, jeśli 480, to orientacja pozioma. Następnie, jeśli orientacja zmieniła się od ostatniego sprawdzenia, uruchomi się funkcja pionowa lub pozioma, w której możesz robić swoje dla każdej orientacji.

Kod (uwaga, wiem, że w kodzie jest pewne powtórzenie, tylko nie zadałem sobie trudu, aby go jeszcze przyciąć!):

// 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!');
}
Danny Connell
źródło
8
Twarde zakodowanie urządzenia do 320 lub 480 nie będzie działać w przyszłości lub z obecnymi telefonami hi-res.
Fresheyeball
1
1) Powinieneś użyć onresizezdarzenia, które uruchomi się natychmiast, a nie w 500 milisekundach 2) Ten kod jest specyficzny dla Androida, onorientationchangezamiast tego użyj dla iPhone'a 3) Sprawdź, czy jest obsługiwany w przeglądarce:"onorientationchange" in window
Dan