ฉันจะตรวจจับการเปลี่ยนแปลงการวางแนวอย่างถูกต้องโดยใช้ Phonegap บน iOS ได้อย่างไร


178

ฉันพบรหัสทดสอบการวางแนวนี้ด้านล่างมองหาวัสดุอ้างอิง JQTouch ทำงานได้อย่างถูกต้องใน iOS Simulator บนมือถือ 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
Atadj

9
ฉันทำได้window.onorientationchange = function() { setTimeout(functionName, 0); };
Kirk Strobeck

11
ทำไมคุณถึงใช้ setTimeout Kirk
backdesk

10
ระวัง! นี่เป็นอุปกรณ์เฉพาะ - องศาหมายถึงความแตกต่างจากการวางแนวมาตรฐานของอุปกรณ์ กล่าวอีกนัยหนึ่งถ้าแท็บเล็ตถูกออกแบบมาเพื่อใช้ในแนวนอนแล้ว 90 จะหมายถึงมันอยู่ในโหมดแนวตั้ง เพื่อหลีกเลี่ยงปัญหานี้ฉันจะตรวจสอบความสูงเทียบกับความกว้างของหน้าต่างเพื่อจัดเก็บการวางแนวและใช้การเปลี่ยนการวางแนวเพื่ออัปเดตสิ่งนี้หากมีการเปลี่ยนแปลง
benallansmith

15
นอกจากนี้ฉันพบว่าการเปลี่ยนการวางแนวยิงก่อนที่ความกว้างและความสูงจะเปลี่ยนไปดังนั้นจึงจำเป็นต้องมีการหน่วงเวลาเล็กน้อยเพื่อตรวจจับการวางแนวอย่างถูกต้องโดยใช้ความกว้างและความสูง สำหรับสิ่งนี้ฉันเก็บการวางแนวปัจจุบันและเมื่อตรวจพบการเปลี่ยนแปลงฉันจะตรวจสอบการเปลี่ยนแปลงในการวางแนวโดยเพิ่มขึ้น 50ms สูงสุดถึง 250ms เมื่อพบความแตกต่างฉันจะอัปเดตหน้าตามนั้นใน Nexus 5 ของฉันมันจะตรวจจับความแตกต่างของความกว้างและความสูงหลังจาก 150ms
benallansmith

24

ฉันใช้window.onresize = function(){ checkOrientation(); } และใน checkOrientation คุณสามารถใช้ window.orientation หรือการตรวจสอบความกว้างของร่างกาย แต่ความคิดคือ "window.onresize" เป็นวิธีเบราว์เซอร์ข้ามส่วนใหญ่อย่างน้อยกับเบราว์เซอร์มือถือและเดสก์ท็อปส่วนใหญ่ที่ฉันเคย โอกาสในการทดสอบด้วย


1
นี่คือจุดที่ดี หากคุณกำลังพัฒนาโดยใช้เทคโนโลยีแบบเผชิญหน้ากับเว็บวิธีนี้จะช่วยให้คุณสามารถดีบักและทดสอบได้ง่ายขึ้นในเบราว์เซอร์แทนที่จะปรับใช้ / จำลองในแต่ละครั้ง
Matt Ray

2
มันไม่โอเคเลย ... เพราะเมื่อคีย์บอร์ดปรากฏขึ้นมันจะปรับขนาด (และนี่ไม่ใช่เพียงกรณีเดียว) ดังนั้นไม่ใหญ่สำหรับเรื่องนี้!
HellBaby

2
@HellBaby เมื่อแป้นพิมพ์ปรากฏขึ้นฟังก์ชั่นจะถูกเรียกใช้อย่างไรก็ตามขึ้นอยู่กับวิธีการที่คุณใช้สำหรับการตรวจจับการวางแนวมันจะตรวจจับว่าการวางแนวไม่ได้เปลี่ยนไปเช่นเดียวกับหน้าต่าง ดังนั้นฉันยังคงยืนหยัดอยู่กับคำตอบ
hndcrftd

1
@ เรนฉันใช้วิธีการนั้นใน Ipad 4 และถูกบังคับให้เปลี่ยนสาเหตุของปัญหานั้น ดังนั้นอาจจะใช้งานได้กับอุปกรณ์บางอย่าง แต่ไม่เหมาะสำหรับทุกคน ..
HellBaby

1
@MattRay คุณสามารถทดสอบการเปลี่ยนแปลงการวางแนวได้อย่างง่ายดายด้วยชุดเครื่องมือ dev ล่าสุดที่สามารถเลียนแบบพฤติกรรมของอุปกรณ์ประเภทนี้ได้
ข้อปฏิบัติ

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

คุณอาจโชคดีที่ได้ค้นหา PhoneGap Google Group สำหรับคำว่า "การวางแนวทาง"

ตัวอย่างหนึ่งที่ฉันอ่านเกี่ยวกับวิธีการตรวจจับทิศทางคือ Pie Guy: ( เกม , ไฟล์ js ) มันคล้ายกับรหัสที่คุณโพสต์ แต่ชอบคุณ ... ฉันไม่สามารถใช้งานได้

ข้อแม้หนึ่ง: EventListener ใช้งานได้สำหรับฉัน แต่ฉันไม่แน่ใจว่านี่เป็นวิธีการที่เข้มข้นเกินไปหรือไม่ จนถึงตอนนี้มันเป็นวิธีเดียวที่ได้ผลสำหรับฉัน แต่ฉันไม่รู้ว่ามีวิธีที่ดีกว่าและคล่องตัวกว่าหรือไม่


UPDATEแก้ไขรหัสด้านบนใช้งานได้แล้ว


โปรดแก้ไขชื่อเหตุการณ์
Dan

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 .There เป็นที่พักใหม่ที่ให้ข้อมูลเพิ่มเติมเกี่ยวกับการวางแนว screen.orientation- แต่ก็ยังคงทดลองและไม่ได้รับการสนับสนุนจากiOS ซาฟารี ดังนั้นเพื่อให้ได้ผลลัพธ์ที่ดีที่สุดคุณอาจต้องใช้ทั้งสองอย่างร่วมกัน: const angle = screen.orientation ? screen.orientation.angle : window.orientation.

  2. ในฐานะที่เป็น @benallansmith กล่าวถึงในความคิดเห็นของเขา , window.onorientationchangeเหตุการณ์ถูกยิงก่อนwindow.onresizeดังนั้นคุณจะไม่ได้รับมิติที่เกิดขึ้นจริงของหน้าจอจนกว่าคุณจะเพิ่มความล่าช้าบางหลังจากเหตุการณ์ orientationchange

  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 ฉันต่อสู้กับปัญหานี้มาหลายวันแล้ว ฉันเคยเห็นตัวแก้เหตุการณ์ eventlist แนะนำสองสามครั้ง แต่ก็ไม่สามารถใช้งานได้

ในที่สุดฉันก็พบวิธีแก้ปัญหาที่แตกต่างออกไป โดยทั่วไปจะตรวจสอบความกว้างของร่างกายเป็นระยะโดยใช้ 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) รหัสนี้เป็นหุ่นยนต์ที่เฉพาะเจาะจงให้ใช้onorientationchangeแทนสำหรับ iPhone 3) การทดสอบถ้ามันได้รับการสนับสนุนในเบราว์เซอร์:"onorientationchange" in window
แดน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.