Làm cách nào để phát hiện chính xác sự thay đổi định hướng bằng Phonegap trên iOS?


178

Tôi tìm thấy mã kiểm tra định hướng dưới đây để tìm tài liệu tham khảo JQTouch. Điều này hoạt động chính xác trong trình giả lập iOS trên Safari di động nhưng không được xử lý chính xác trong Phonegap. Dự án của tôi đang chạy vào cùng một vấn đề đang giết chết trang thử nghiệm này. Có cách nào để cảm nhận sự thay đổi định hướng bằng cách sử dụng JavaScript trong Phonegap không?

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

Câu trả lời:


297

Đây là những gì tôi làm:

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


Cập nhật tháng 5 năm 2019: window.orientation là một tính năng không dùng nữa và không được hầu hết các trình duyệt hỗ trợ theo MDN . Sự orientationchangekiện này được liên kết với window.orientation và do đó có lẽ không nên được sử dụng.


3
Đó là giải pháp duy nhất phù hợp với tôi từ cuộc thảo luận này :) +1
Atadj

9
Tôi đã làmwindow.onorientationchange = function() { setTimeout(functionName, 0); };
Kirk Strobeck

11
Không thích thú, tại sao bạn lại sử dụng setTimeout Kirk?
backdesk

10
Hãy cẩn thận! Đây là thiết bị cụ thể - độ liên quan đến sự khác biệt so với định hướng tiêu chuẩn của thiết bị. Nói cách khác, nếu máy tính bảng được thiết kế để sử dụng theo chiều ngang thì 90 có nghĩa là nó ở chế độ dọc. Để giải quyết vấn đề này, ban đầu tôi kiểm tra chiều cao so với chiều rộng của cửa sổ để lưu trữ hướng và sử dụng định hướng để cập nhật điều này nếu có thay đổi.
benallansmith

15
Ngoài ra, tôi đã thấy rằng bộ chuyển đổi định hướng kích hoạt trước khi thay đổi chiều rộng và chiều cao, do đó cần một chút độ trễ để phát hiện hướng chính xác bằng chiều rộng và chiều cao. Đối với điều này, tôi lưu trữ hướng hiện tại và khi phát hiện thay đổi, tôi kiểm tra sự thay đổi về hướng trong khoảng tăng 50ms lên đến 250ms. Khi tìm thấy sự khác biệt, tôi sẽ cập nhật trang tương ứng. Trên Nexus 5 của tôi, nó thường phát hiện chênh lệch chiều rộng và chiều cao sau 150ms.
benallansmith

24

Tôi sử dụng window.onresize = function(){ checkOrientation(); } Và trong checkOrientation, bạn có thể sử dụng window.orientation hoặc body width check nhưng ý tưởng là, "window.onresize" là phương pháp trình duyệt chéo nhất, ít nhất là với phần lớn các trình duyệt trên thiết bị di động và máy tính để bàn mà tôi đã có cơ hội thử nghiệm với.


1
Đây là một điểm tuyệt vời. Nếu bạn đang phát triển bằng cách sử dụng công nghệ đối mặt với web, phương pháp này cho phép bạn gỡ lỗi và kiểm tra dễ dàng hơn trong trình duyệt thay vì triển khai / mô phỏng mỗi lần.
Matt Ray

2
Điều này không ổn chút nào ... vì khi bàn phím xuất hiện, nó sẽ thay đổi kích thước (và đây không phải là trường hợp duy nhất). Vì vậy, một không lớn cho điều này!
HellBaby

2
@HellBaby Khi bàn phím xuất hiện, chức năng sẽ được gọi, tuy nhiên, tùy thuộc vào phương thức bạn sử dụng để phát hiện hướng, nó sẽ phát hiện ra rằng hướng KHÔNG THAY ĐỔI, như trường hợp của window.orientation. Vì vậy, tôi vẫn đứng trước câu trả lời của tôi.
hndcrftd

1
@Raine Tôi đã sử dụng phương pháp đó trên Ipad 4 và buộc phải thay đổi nguyên nhân của vấn đề đó. Vì vậy, có thể nó hoạt động cho một số thiết bị nhưng không phải cho tất cả ..
HellBaby

1
@MattRay Bạn có thể dễ dàng kiểm tra các thay đổi hướng với các bộ công cụ dev mới nhất có khả năng mô phỏng loại hành vi thiết bị này.
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
Bạn có thể đính kèm nó vào một resizesự kiện. Tuy nhiên, IIRC, các truy vấn này sẽ không hoạt động chính xác với bàn phím lên.
adi518

12

Tôi cũng khá mới với iOS và Phonegap, nhưng tôi đã có thể làm điều này bằng cách thêm vào một eventListener. Tôi đã làm điều tương tự (sử dụng ví dụ bạn tham khảo) và không thể làm cho nó hoạt động. Nhưng điều này dường như để thực hiện các mẹo:

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

Bạn có thể gặp may mắn khi tìm kiếm Nhóm Google của PhoneGap với cụm từ "định hướng" .

Một ví dụ tôi đọc là một ví dụ về cách phát hiện định hướng là Pie Guy: ( trò chơi , tệp js ). Nó tương tự như mã bạn đã đăng, nhưng giống như bạn ... Tôi không thể làm cho nó hoạt động được.

Một cảnh báo: eventListener đã làm việc cho tôi, nhưng tôi không chắc liệu đây có phải là một cách tiếp cận quá chuyên sâu hay không. Cho đến nay, đó là cách duy nhất phù hợp với tôi, nhưng tôi không biết liệu có cách nào tốt hơn, hợp lý hơn không.


CẬP NHẬT đã sửa mã ở trên, nó hoạt động ngay bây giờ


Xin vui lòng sửa tên sự kiện
Dan

5

Trong khi làm việc với orientationchangesự kiện, tôi cần thời gian chờ để có được kích thước chính xác của các thành phần trong trang, nhưng matchMedia hoạt động tốt. Mã cuối cùng của tôi:

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

Tôi tin rằng câu trả lời chính xác đã được đăng và chấp nhận, nhưng có một vấn đề mà tôi đã tự trải nghiệm và một số người khác đã đề cập ở đây.

Trên một số nền tảng nhất định, các thuộc tính khác nhau như kích thước cửa sổ ( window.innerWidth, window.innerHeight) và thuộc window.orientationtính sẽ không được cập nhật theo thời gian sự kiện "orientationchange"đã phát sinh. Nhiều lần, tài sản window.orientationchỉ undefinedtrong vài mili giây sau khi khai hỏa "orientationchange"(ít nhất là trong Chrome trên iOS).

Cách tốt nhất mà tôi tìm thấy để xử lý vấn đề này là:

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

Tôi đang kiểm tra xem liệu định hướng có được xác định không hoặc nếu định hướng bằng với định hướng cuối cùng được phát hiện. Nếu một trong hai là đúng, tôi đợi mười mili giây và sau đó phân tích lại hướng. Nếu định hướng là một giá trị phù hợp, tôi gọi các showXOrientationhàm. Nếu định hướng không hợp lệ, tôi tiếp tục lặp chức năng kiểm tra của mình, đợi mười mili giây mỗi lần, cho đến khi nó hợp lệ.

Bây giờ, tôi sẽ tạo một JSFiddle cho việc này, như tôi thường làm, nhưng JSFiddle đã không hoạt động cho tôi và lỗi hỗ trợ của tôi cho nó đã bị đóng vì không ai khác báo cáo vấn đề tương tự. Nếu bất cứ ai khác muốn biến điều này thành một JSFiddle, vui lòng tiếp tục.

Cảm ơn! Tôi hi vọng cái này giúp được!


FYI, trong thử nghiệm ban đầu, tôi đã thấy một vấn đề: Tôi xoay theo chiều kim đồng hồ một vài lần và một cảnh báo cho biết "Định hướng cảnh quan: 180" mặc dù thiết bị của tôi được định hướng vật lý như một bức chân dung.
MarsAndBack

2

đây là những gì tôi đã làm:

window.addEventListener('orientationchange', doOnOrientationChange);

function doOnOrientationChange()
{
      if (screen.height > screen.width) {
         console.log('portrait');
      } else {
         console.log('landscape');
      }
}

2

Mặc dù câu hỏi chỉ đề cập đến việc sử dụng PhoneGap và iOS và mặc dù nó đã được trả lời, tôi có thể thêm một vài điểm vào câu hỏi rộng hơn về việc phát hiện hướng màn hình với JS vào năm 2019:

  1. window.orientationthuộc tính không được hỗ trợ và không được hỗ trợ bởi trình duyệt Android . Có một thuộc tính mới hơn cung cấp thêm thông tin về định hướng - screen.orientation. Nhưng nó vẫn đang thử nghiệm và không được iOS Safari hỗ trợ . Vì vậy, để đạt được kết quả tốt nhất có lẽ bạn cần sử dụng kết hợp cả hai : const angle = screen.orientation ? screen.orientation.angle : window.orientation.

  2. Như @benallansmith đã đề cập trong bình luận của mình , window.onorientationchangesự kiện đã được kích hoạt trước đó window.onresize, vì vậy bạn sẽ không nhận được kích thước thực của màn hình trừ khi bạn thêm một số độ trễ sau sự kiện trao đổi định hướng.

  3. Có một Plugin Định hướng màn hình Cordova để hỗ trợ các trình duyệt di động cũ hơn, nhưng tôi tin rằng ngày nay không cần sử dụng nó nữa.

  4. Cũng có một screen.onorientationchangesự kiện, nhưng nó không được dùng nữa và không nên sử dụng. Đã thêm chỉ để hoàn thành câu trả lời.

Trong trường hợp sử dụng của tôi, tôi không quan tâm nhiều đến hướng thực tế, mà là về chiều rộng và chiều cao thực tế của cửa sổ, rõ ràng là thay đổi theo hướng. Vì vậy, tôi đã sử dụng resizesự kiện để tránh xử lý sự chậm trễ giữa orientationchangesự kiện và hiện thực hóa kích thước cửa sổ:

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

Lưu ý 1: Tôi đã sử dụng cú pháp EcmaScript 6 ở đây, đảm bảo biên dịch nó thành ES5 nếu cần.

Lưu ý 2: window.onresizesự kiện cũng được kích hoạt khi bàn phím ảo được bật , không chỉ khi thay đổi hướng.


1

Tôi đã tìm thấy mã này để phát hiện xem thiết bị có ở hướng ngang hay không và trong trường hợp này hãy thêm một trang giật gân có nội dung "thay đổi hướng để xem trang web". Nó hoạt động trên điện thoại iOS, Android và windows. Tôi nghĩ rằng điều này rất hữu ích vì nó khá thanh lịch và tránh đặt chế độ xem ngang cho trang web di động. Mã đang hoạt động rất tốt. Điều duy nhất không hoàn toàn thỏa mãn là nếu ai đó tải trang đang ở chế độ xem ngang thì trang giật gân sẽ không xuất hiện.

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

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

Sau đây làm việc cho tôi:

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

Tôi cần thời gian chờ vì giá trị của window.orientationkhông cập nhật ngay lập tức


-3

Tôi đang tạo một ứng dụng jQTouch trong PhoneGap cho iPhone. Tôi đã chiến đấu với vấn đề này trong nhiều ngày. Tôi đã thấy giải pháp cho sự kiện được đề xuất một vài lần, nhưng không thể làm cho nó hoạt động được.

Cuối cùng, tôi đã đưa ra một giải pháp khác. Về cơ bản, nó kiểm tra chiều rộng của cơ thể theo định kỳ bằng cách sử dụng giải quyết. Nếu chiều rộng là 320 thì hướng là dọc, nếu 480 thì ngang. Sau đó, nếu hướng đã thay đổi kể từ lần kiểm tra cuối cùng, nó sẽ kích hoạt chức năng công cụ dọc hoặc chức năng công cụ phong cảnh nơi bạn có thể thực hiện việc của mình cho mỗi hướng.

Mã (lưu ý, tôi biết có một số sự lặp lại trong mã, chỉ cần không bận tâm để cắt giảm mã này!):

// 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
Mã hóa cứng thiết bị thành 320 hoặc 480 sẽ không hoạt động trong tương lai hoặc với các điện thoại độ phân giải cao hiện tại.
Fresheyeball

1
1) Bạn nên sử dụng onresizesự kiện sẽ kích hoạt ngay lập tức, không phải trong 500 giây 2) Mã này dành riêng cho Android, sử dụng onorientationchangethay cho iPhone 3) Kiểm tra xem nó có được hỗ trợ trong trình duyệt không:"onorientationchange" in window
Dan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.