ตรวจจับการหมุนของโทรศัพท์ Android ในเบราว์เซอร์ด้วย JavaScript


188

ฉันรู้ว่าใน Safari บน iPhone คุณสามารถตรวจจับทิศทางของหน้าจอและเปลี่ยนทิศทางได้โดยฟังonorientationchangeเหตุการณ์และสอบถามwindow.orientationมุม

เป็นไปได้ไหมในเบราว์เซอร์บนโทรศัพท์ Android?

เพื่อความชัดเจนฉันถามว่าการหมุนของอุปกรณ์ Android สามารถตรวจพบได้โดยJavaScript ที่ทำงานบนหน้าเว็บมาตรฐานหรือไม่ เป็นไปได้ใน iPhone และฉันสงสัยว่ามันสามารถทำได้สำหรับโทรศัพท์ Android

คำตอบ:


214

ในการตรวจจับการเปลี่ยนแปลงการวางแนวบนเบราว์เซอร์ Android ให้แนบผู้ฟังเข้ากับorientationchangeหรือresizeเหตุการณ์บนwindow:

// Detect whether device supports orientationchange event, otherwise fall back to
// the resize event.
var supportsOrientationChange = "onorientationchange" in window,
    orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";

window.addEventListener(orientationEvent, function() {
    alert('HOLY ROTATING SCREENS BATMAN:' + window.orientation + " " + screen.width);
}, false);

ตรวจสอบwindow.orientationคุณสมบัติเพื่อหาวิธีการวางแนวของอุปกรณ์ ด้วยโทรศัพท์ Android screen.widthหรือscreen.heightยังอัปเดตเมื่อหมุนอุปกรณ์ (นี่ไม่ใช่กรณีของ iPhone)


มันใช้งานได้จริงเหรอ? ฉันลอง jquery $ (หน้าต่าง) .bind ("ปฐมนิเทศ", fn); แต่มันใช้งานไม่ได้ฉันต้องใช้แบบฟอร์มด้านบนหรือไม่ ฉันพยายาม "onorientationchange" ในหน้าต่างก็ retuns เท็จ
Ayyash

มันใช้งานได้ดี Ayyash - จุดทั้งที่นี่ว่าเมื่อ "orientationchange" ไม่ได้รับการสนับสนุนก็จะตกกลับไปที่ "ปรับขนาด"
Dror

9
บน Droid นี่มันบ้ามาก มันเตือนหน้าจอแบนด์วิดธ์ของ 320 เมื่อโทรศัพท์หมุนในโหมดแนวนอนและมันจะตรวจจับหน้าจอแบนด์วิดธ์ 569 เมื่อโทรศัพท์หมุนในโหมดแนวตั้ง! มาทำไม
IgorGanapolsky

1
เพื่อชี้แจง: ผู้ที่มองหาโซลูชันที่ใช้กับ iOS ได้ควรดูที่คำตอบของฉันแบบสองบิต
mklement0

3
ไม่จำเป็นต้องใช้แฮ็คของสองบิตสำหรับ iOS เพียงใช้หน้าจอแบนด์วิดท์และหน้าจอความสูงบน Android และบน iOS ใช้ window.innerWidth และ window.innerHeight
Justin

225

ที่เกิดขึ้นจริงพฤติกรรมที่แตกต่างกันในอุปกรณ์จะไม่สอดคล้องกัน เหตุการณ์การปรับขนาดและการวางแนวสามารถดำเนินการในลำดับที่แตกต่างกันด้วยความถี่ที่แตกต่างกัน นอกจากนี้ค่าบางอย่าง (เช่น screen.width และ window.orientation) จะไม่เปลี่ยนแปลงเมื่อคุณคาดหวัง หลีกเลี่ยงหน้าจอแบนด์วิดท์ - มันจะไม่เปลี่ยนเมื่อหมุนใน iOS

วิธีการที่เชื่อถือได้คือการฟังทั้งการปรับขนาดและการวางแนวเหตุการณ์การเปลี่ยนแปลง (ด้วยการสำรวจความคิดเห็นเพื่อความปลอดภัย) และในที่สุดคุณจะได้รับค่าที่ถูกต้องสำหรับการปฐมนิเทศ ในการทดสอบของฉันอุปกรณ์ Android บางครั้งล้มเหลวในการเริ่มต้นเหตุการณ์เมื่อหมุนเต็ม 180 องศาดังนั้นฉันจึงได้รวมชุดช่วงเวลาเพื่อสำรวจความคิดเห็น

var previousOrientation = window.orientation;
var checkOrientation = function(){
    if(window.orientation !== previousOrientation){
        previousOrientation = window.orientation;
        // orientation changed, do your magic here
    }
};

window.addEventListener("resize", checkOrientation, false);
window.addEventListener("orientationchange", checkOrientation, false);

// (optional) Android doesn't always fire orientationChange on 180 degree turns
setInterval(checkOrientation, 2000);

นี่คือผลลัพธ์จากอุปกรณ์สี่อย่างที่ฉันทดสอบ (ขออภัยสำหรับตาราง ASCII แต่ดูเหมือนจะเป็นวิธีที่ง่ายที่สุดในการนำเสนอผลลัพธ์) นอกเหนือจากความสอดคล้องระหว่างอุปกรณ์ iOS แล้วยังมีอุปกรณ์ที่หลากหลายมากมาย หมายเหตุ: เหตุการณ์ต่าง ๆ ที่ระบุไว้ในลำดับที่พวกเขายิง

| ================================================= ============================= |
| อุปกรณ์ | เหตุการณ์ที่เกิดขึ้น ปฐมนิเทศ | InnerWidth ความกว้างของหน้าจอ
| ================================================= ============================= |
| iPad 2 | ปรับขนาด | 0 | 1024 | 768 |
| (กับทิวทัศน์) ปฐมนิเทศ | 90 | 1024 | 768 |
| ---------------- + + ------------------- ------------ - + + ------------ -------------- |
| iPad 2 | ปรับขนาด | 90 | 768 | 768 |
| (เป็นแนวตั้ง) ปฐมนิเทศ | 0 | 768 | 768 |
| ---------------- + + ------------------- ------------ - + + ------------ -------------- |
| iPhone 4 | ปรับขนาด | 0 | 480 | 320 |
| (กับทิวทัศน์) ปฐมนิเทศ | 90 | 480 | 320 |
| ---------------- + + ------------------- ------------ - + + ------------ -------------- |
| iPhone 4 | ปรับขนาด | 90 | 320 | 320 |
| (เป็นแนวตั้ง) ปฐมนิเทศ | 0 | 320 | 320 |
| ---------------- + + ------------------- ------------ - + + ------------ -------------- |
| โทรศัพท์ Droid ปฐมนิเทศ | 90 | 320 | 320 |
| (กับทิวทัศน์) ปรับขนาด | 90 | 569 | 569 |
| ---------------- + + ------------------- ------------ - + + ------------ -------------- |
| โทรศัพท์ Droid ปฐมนิเทศ | 0 | 569 | 569 |
| (เป็นแนวตั้ง) ปรับขนาด | 0 | 320 | 320 |
| ---------------- + + ------------------- ------------ - + + ------------ -------------- |
| Samsung Galaxy | ปฐมนิเทศ | 0 | 400 | 400 |
| แท็บเล็ต ปฐมนิเทศ | 90 | 400 | 400 |
| (กับทิวทัศน์) ปฐมนิเทศ | 90 | 400 | 400 |
| | ปรับขนาด | 90 | 683 | 683 |
| | ปฐมนิเทศ | 90 | 683 | 683 |
| ---------------- + + ------------------- ------------ - + + ------------ -------------- |
| Samsung Galaxy | ปฐมนิเทศ | 90 | 683 | 683 |
| แท็บเล็ต ปฐมนิเทศ | 0 | 683 | 683 |
| (เป็นแนวตั้ง) ปฐมนิเทศ | 0 | 683 | 683 |
| | ปรับขนาด | 0 | 400 | 400 |
| | ปฐมนิเทศ | 0 | 400 | 400 |
| ---------------- + + ------------------- ------------ - + + ------------ -------------- |

ในโปรแกรมจำลอง iOS5 หากคุณรีเฟรชในแนวนอนแล้วหมุนรหัสนี้จะไม่ทำงาน
ทำงาน

1
คำตอบที่ดี previousOrientationควรเริ่มต้นด้วยการวางแนวปัจจุบันนั้น: var previousOrientation = window.orientation;หากคุณต้องการละเว้นการหมุน 180 องศานั่นคือคุณไม่จำเป็นต้องแยกแยะความแตกต่างระหว่างแนวนอนด้านซ้ายหรือด้านขวาและชุดตัวเลือกคว่ำ ในฐานะบรรทัดแรกของcheckOrientation(): if (0 === (previousOrientation + window.orientation) % 180) return;อย่างไรก็ตามหากไม่มีsetTimeoutกลอุบายเพิ่มเติมคุณจะได้รับประโยชน์จากสิ่งนี้ใน iOS เท่านั้นซึ่งการหมุนรอบ 180 องศาที่รวดเร็วเพียงสร้างเหตุการณ์เดียว orientationchange
mklement0

ขอบคุณ @mklement ฉัน tweaked รหัสเพื่อเริ่มต้นการออกก่อนหน้านี้
สองคนโง่

ขอบคุณสำหรับข้อมูลที่ยอดเยี่ยม นี่คือสิ่งที่ฉันกำลังทำอยู่เพราะ windows phone 8.1 ไม่มีคุณลักษณะการปรับขนาดหรือการวางแนวเมื่อคุณใช้คอร์โดวา ใช้วิธีการ setInterval เช่นเดียวกับที่ไม่ปลอดภัย
ความสมบูรณ์แบบ

@ mklement0 จนถึงทุกวันนี้ window.orientation จะไม่ถูกกำหนดบน windows phone 8.1 เสมอ
ความสมบูรณ์แบบ

39

คำตอบที่ยอดเยี่ยมของ two-bit-โง่ให้พื้นหลังทั้งหมด แต่ให้ฉันลองสรุปย่อในทางปฏิบัติของวิธีการจัดการการเปลี่ยนแปลงปฐมนิเทศใน iOS และ Android :

  • หากคุณสนใจเฉพาะขนาดหน้าต่าง (สถานการณ์ทั่วไป) - และไม่เกี่ยวกับการวางแนวเฉพาะ:
    • จัดการกับresizeเหตุการณ์เท่านั้น
    • ในการจัดการของคุณดำเนินการwindow.innerWidthและwindow.InnerHeightเท่านั้น
    • ห้ามใช้window.orientation- มันจะไม่เป็นปัจจุบันบน iOS
  • หากคุณสนใจเกี่ยวกับการปฐมนิเทศที่เฉพาะเจาะจง :
    • จับเพียงresizeเหตุการณ์บน Android และเพียงorientationchangeเหตุการณ์บน iOS
    • ในตัวจัดการของคุณดำเนินการwindow.orientation(และwindow.innerWidthและwindow.InnerHeight)

วิธีการเหล่านี้ให้ประโยชน์เล็กน้อยในการจดจำการวางแนวก่อนหน้าและการเปรียบเทียบ:

  • วิธีการขนาดเท่านั้นยังทำงานได้ในขณะที่พัฒนาบนเบราว์เซอร์เดสก์ท็อปที่สามารถจำลองอุปกรณ์มือถือเช่น Chrome 23 ได้ ( window.orientationไม่สามารถใช้ได้กับเบราว์เซอร์เดสก์ท็อป)
  • ไม่จำเป็นต้องมีตัวแปรระดับโกลบอล / ไม่ระบุชื่อไฟล์ระดับฟังก์ชั่นห่อหุ้ม

ปัญหาคือว่าเมื่อเหตุการณ์การปรับขนาดหรือการวางแนวยิง window.innerWidth รายงานที่ไม่ถูกต้องและอุปกรณ์ Droid
albanx

@albanx ที่ยังคงมีปัญหาใน chrome บน ios: / safari is tho ดี
oldboy

12

คุณสามารถฟังเหตุการณ์การปรับขนาดหน้าต่างได้ตลอดเวลา หากในเหตุการณ์นั้นหน้าต่างเริ่มจากที่สูงกว่ากว้างถึงกว้างกว่าสูง (หรือกลับกัน) คุณค่อนข้างแน่ใจว่าการวางแนวโทรศัพท์นั้นเพิ่งเปลี่ยนไป


นั่นเป็นความคิดที่ดีฉันจะพยายามที่ (และขอให้เพื่อนของฉันกับโทรศัพท์ Android ไปทดสอบ!)
philnash

ฉันเพิ่งรู้ว่าวิธีนี้ไม่ได้ให้การวางแนวของโทรศัพท์ ฉันจะรู้ว่ามันเป็นแนวตั้งหรือแนวนอน แต่ไม่ใช่ถ้าคว่ำหรือหันไปทางซ้ายหรือไปทางขวา มีความคิดเพิ่มเติมหรือไม่
philnash

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

1
นั่นเป็นเพียงเล็กน้อยที่รุนแรง ฉันสนใจที่จะทราบเพื่อให้ฉันสามารถแสดงเนื้อหาที่แตกต่างกันตามการวางแนวของหน้าจอซึ่งอาจเป็นได้ถึง 4 หน้าที่แตกต่างกันโดยกำหนดให้เบราว์เซอร์รู้ว่ามีการหมุนด้วย 0, 90, 180 และ 270 องศาหรือไม่ ทั้งหมดนี้เป็นไปได้ใน JavaScript บน iPhone และเป็นสาเหตุที่ฉันถาม
philnash

ฉันยังคงมีช่วงเวลาที่ยากลำบากในการแสดงให้เห็นว่าหน้าเว็บสามารถทำอะไรที่แตกต่างกันได้บ้างเมื่ออุปกรณ์ที่แสดงผลนั้นหมุนไปแล้ว 270 องศา แต่ถ้าคุณบอกว่าคุณใช้งานได้อย่างถูกต้องแล้ว ในกรณีนี้: ฉันขอโทษ แต่ฉันไม่รู้ว่าเบราว์เซอร์ Android ให้รายละเอียดในระดับนี้หรือไม่
Joel Mueller

3

เป็นไปได้ใน HTML5
คุณสามารถอ่านเพิ่มเติม (และลองการสาธิตสด) ที่นี่: http://slides.html5rocks.com/#slide-orientation

window.addEventListener('deviceorientation', function(event) {
    var a = event.alpha;
    var b = event.beta;
    var g = event.gamma;
}, false);

นอกจากนี้ยังรองรับเบราว์เซอร์ deskop แต่จะคืนค่าเดิมเสมอ


4
เหตุการณ์นี้มากขึ้นสำหรับการเข้าถึงเซ็นเซอร์ตรวจจับความเคลื่อนไหวถึงแม้ว่าฉันคิดว่ามันสามารถใช้ในการตรวจจับการเปลี่ยนทิศทาง
René

ใน Android Galaxy S2 ของฉันไม่รองรับเบราว์เซอร์หุ้นหรือ Dolphin Browser แต่ทำงานได้ดีกับมือถือ Firefox
Eduardo

3

ผมมีปัญหาเหมือนกัน. ฉันใช้ Phonegap และ Jquery mobile สำหรับอุปกรณ์ Adroid ในการปรับขนาดอย่างถูกต้องฉันต้องตั้งค่าการหมดเวลา:

$(window).bind('orientationchange',function(e) {
  fixOrientation();
});

$(window).bind('resize',function(e) {
  fixOrientation();
});

function fixOrientation() {

    setTimeout(function() {

        var windowWidth = window.innerWidth;

        $('div[data-role="page"]').width(windowWidth);
        $('div[data-role="header"]').width(windowWidth);
        $('div[data-role="content"]').width(windowWidth-30);
        $('div[data-role="footer"]').width(windowWidth);

    },500);
}

2

นี่คือทางออก:

var isMobile = {
    Android: function() {
        return /Android/i.test(navigator.userAgent);
    },
    iOS: function() {
        return /iPhone|iPad|iPod/i.test(navigator.userAgent);
    }
};
if(isMobile.Android())
    {
        var previousWidth=$(window).width();
        $(window).on({
        resize: function(e) {
        var YourFunction=(function(){

            var screenWidth=$(window).width();
            if(previousWidth!=screenWidth)
            {
                previousWidth=screenWidth;
                alert("oreientation changed");
            }

        })();

        }
    });

    }
    else//mainly for ios
    {
        $(window).on({
            orientationchange: function(e) {
               alert("orientation changed");
            }   
        });
    }

นี่เป็นวิธีแก้ปัญหาที่ทำงานได้ดีที่สุดสำหรับฉันฉันรู้ว่ามันไม่ถูกต้อง 100% แต่คุณสามารถตรวจจับแนวนอนและแนวตั้งได้โดยใช้: var screenWidth = $ (หน้าต่าง). ความกว้าง (); var screenHeight = $ (หน้าต่าง) .height (); ถ้า (screenWidth> screenHeight) {doSomething (); }
math0ne

อันนี้เป็นทางออกสำหรับฉันบนแท็บเล็ต Android เส็งเคร็ง window.onresize, attachevent และ addeventlistener ล้มเหลวในหลายเหตุการณ์ (ปรับขนาด, เปิดใช้งานใหม่, ปรับทิศทาง, เปลี่ยนอุปกรณ์) เฉพาะ Jquery $ (หน้าต่าง) .on () เท่านั้นที่ทำงานได้
Lego

1

gotcha อื่น - แท็บเล็ต Android บางรุ่น (Motorola Xoom ฉันเชื่อและ Elonex ระดับต่ำสุดที่ฉันกำลังทำการทดสอบบางอย่างอาจเป็นอย่างอื่น) มีการตั้งค่า accelerometers เพื่อให้ window.orientation == 0 ในโหมด LANDSCAPE ไม่ใช่แนวตั้ง !


1

คุณสามารถลองวิธีแก้ปัญหาเข้ากันได้กับเบราว์เซอร์ทั้งหมด

ต่อไปนี้คือorientationchangepic ความเข้ากันได้: ความเข้ากันได้ ดังนั้นฉันเขียนorientaionchangepolyfill มันขึ้นอยู่กับคุณลักษณะ @media เพื่อแก้ไขการวางแนวยูทิลิตี้ไลบรารี —— Orientchange -fix

window.addEventListener('orientationchange', function(){
 if(window.neworientation.current === 'portrait|landscape'){
    // do something……
 } else {
    // do something……
 }
}, false);

0

เป็นที่น่าสังเกตว่าใน Epic 4G Touch ของฉันฉันต้องตั้งค่ามุมมองเว็บเพื่อใช้ WebChromeClient ก่อนที่จะมีการเรียกใช้ android javascript

webView.setWebChromeClient(new WebChromeClient());

0

วิธีเบราว์เซอร์ข้าม

$(window).on('resize orientationchange webkitfullscreenchange mozfullscreenchange fullscreenchange',  function(){
//code here
});

-1

ความช่วยเหลือเล็กน้อยจากคำตอบของคนสองคน:

ตามที่อธิบายไว้ในตารางในเหตุการณ์ "ปฐมนิเทศ" ของ droid โทรศัพท์จะถูกเรียกใช้เร็วกว่าเหตุการณ์ "ปรับขนาด" ดังนั้นการปิดกั้นการโทรปรับขนาดครั้งต่อไป (เนื่องจากคำสั่ง if) คุณสมบัติความกว้างยังคงไม่ถูกตั้งค่า

วิธีแก้ปัญหาแม้ว่าอาจไม่ใช่งานที่สมบูรณ์แบบก็อาจจะไม่ส่งเหตุการณ์ "ปฐมนิเทศ" ที่สามารถเก็บถาวรได้โดยการรวมคำสั่งเหตุการณ์ "ปฐมนิเทศ" ไว้ในคำสั่ง "if":

if (!navigator.userAgent.match(/android/i))
{
    window.addEventListener("orientationchange", checkOrientation, false);
}

หวังว่ามันจะช่วย

(ทำการทดสอบบน Nexus S)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.