使用JavaScript在浏览器中检测安卓手机的旋转。

194

我知道在iPhone的Safari浏览器上,您可以通过监听onorientationchange事件并查询window.orientation角度来检测屏幕方向和方向变化。

这在Android手机浏览器中是否也可行?

明确一下,我想问的是是否可以通过运行在标准网页上的JavaScript来检测Android设备的旋转。在iPhone上是可能的,我想知道是否也适用于Android手机。

12个回答

235
不同设备的实际行为是不一致的。调整大小和方向更改事件可能以不同的频率和不同的顺序触发。此外,某些值(例如screen.width和window.orientation)并不总是在你期望的时候更改。避免使用screen.width--在iOS中旋转时它不会改变。
可靠的方法是同时监听调整大小和方向更改事件(带有一些轮询作为安全措施),最终您将获得方向的有效值。在我的测试中,Android设备有时无法在旋转180度时触发事件,因此我还包括了一个setInterval来轮询方向。
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 | screen.width | |==============================================================================| | iPad 2 | resize | 0 | 1024 | 768 | | (转到横屏) | orientationchange | 90 | 1024 | 768 | |----------------+-------------------+-------------+------------+--------------| | iPad 2 | resize | 90 | 768 | 768 | | (转到竖屏) | orientationchange | 0 | 768 | 768 | |----------------+-------------------+-------------+------------+--------------| | iPhone 4 | resize | 0 | 480 | 320 | | (转到横屏) | orientationchange | 90 | 480 | 320 | |----------------+-------------------+-------------+------------+--------------| | iPhone 4 | resize | 90 | 320 | 320 | | (转到竖屏) | orientationchange | 0 | 320 | 320 | |----------------+-------------------+-------------+------------+--------------| | 安卓手机 | orientationchange | 90 | 320 | 320 | | (转到横屏) | resize | 90 | 569 | 569 | |----------------+-------------------+-------------+------------+--------------| | 安卓手机 | orientationchange | 0 | 569 | 569 | | (转到竖屏) | resize | 0 | 320 | 320 | |----------------+-------------------+-------------+------------+--------------| | 三星平板 | orientationchange | 0 | 400 | 400 | | | orientationchange | 90 | 400 | 400 | | (转到横屏) | orientationchange | 90 | 683 | 683 | | | resize | 90 | 683 | 683 | | | orientationchange | 90 | 683 | 683 | |----------------+-------------------+-------------+------------+--------------| | 三星平板 | orientationchange | 90 | 683 | 683 | | | orientationchange | 0 | 683 | 683 | | (转到竖屏) | orientationchange | 0 | 400 | 400 | | | resize | 0 | 400 | 400 | | | orientationchange | 0 | 400 | 400 | |----------------+-------------------+-------------+------------+--------------|

在iOS5模拟器中,如果您在横向刷新后旋转,则此代码不会触发。 - worked
1
很好的答案。previousOrientation 应该用当前方向进行初始化:var previousOrientation = window.orientation; 如果您想忽略 180 度旋转,即您不需要区分左右横屏和上下颠倒或非颠倒变体,请将以下内容添加为 checkOrientation() 的第一行:if (0 === (previousOrientation + window.orientation) % 180) return; 然而,如果没有额外的 setTimeout 技巧,您只能在 iOS 上受益,因为迅速的 180 度旋转只会创建一个 orientationchange 事件。 - mklement0
感谢@mklement,我调整了代码以初始化previousOrientation。 - two-bit-fool
感谢提供这么棒的信息。因为在使用cordova时,Windows Phone 8.1没有提供resize或orientationchange事件,所以我一直很困扰。最终不得不采用setInterval和failsafe来解决问题。 - Perfection
@mklement0 到目前为止,在 Windows Phone 8.1 上,window.orientation 总是未定义的。 - Perfection

220

要在安卓浏览器上检测方向变化,请将监听器附加到windoworientationchangeresize事件:


// 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.widthscreen.height在设备旋转时也会更新(但iPhone不会)。


它运行良好。Ayyash - 这里的重点是当“orientationchange”不受支持时,它将回退到“resize”。 - Dror
9
在Droid手机上这完全是疯狂的。当手机在横屏模式下旋转时,它会触发屏幕宽度为320的警报,而当手机在竖屏模式下旋转时,则检测到屏幕宽度为569!这是怎么回事? - IgorGanapolsky
1
只是为了澄清:那些寻找在iOS上也能工作的解决方案的人应该查看two-bit-fool或我的答案。 - mklement0
4
在 iOS 上不需要使用低劣的 hack。在 Android 上,只需使用 screen.width 和 screen.height,在 iOS 上则使用 window.innerWidth 和 window.innerHeight。 - Justin
不错的方法。console.log('/\/\/ BATMAN \ /\/\'); - Marco Ramires
显示剩余3条评论

43

如果你只关心窗口尺寸(典型情况),而不关心具体方向:

  • 仅处理resize事件。
  • 在处理程序中,只操作window.innerWidthwindow.InnerHeight
  • 不要使用window.orientation - 在iOS上它不会是当前值。

如果你关心具体方向:

  • 在Android上仅处理resize事件,在iOS上仅处理orientationchange事件。
  • 在处理程序中,操作window.orientation(以及window.innerWidthwindow.InnerHeight)。

这些方法相对于记住先前的方向并进行比较有轻微的优势:

  • 仅尺寸方法也适用于可以模拟移动设备的桌面浏览器,例如Chrome 23。(在桌面浏览器上不支持window.orientation)。
  • 不需要全局/匿名文件级函数包装器级变量。

问题在于当调整大小或方向事件触发时,window.innerWidth 报告错误,并且Droid设备。 - albanx
@albanx 在iOS的Chrome上仍然存在这个问题:/ 但Safari没问题 - oldboy
这很有用!它让我意识到我不关心方向,这使事情变得容易了许多。 - Mmm

12

您可以始终侦听窗口调整大小事件。如果在该事件上,窗口从比宽度更高的状态变为比高度更宽的状态(反之亦然),那么您可以非常确定手机方向刚刚发生了更改。


我刚刚意识到这种方法无法提供手机的方向。我可以知道它是横屏还是竖屏,但无法确定它是倒置、左转还是右转。还有其他想法吗? - philnash
1
这有点严厉。我很感兴趣了解屏幕方向,以便根据其方向显示不同的内容,这可能需要最多4个不同的页面,需要浏览器知道它是否被旋转了0、90、180和270度。这在iPhone上完全可以通过JavaScript实现,这也是我提出问题的原因。 - philnash
我仍然很难想象一个网页在旋转270度的设备上渲染时可以有什么不同的有用之处,但如果你说你有一个有效的用例,我就不会争辩了。在这种情况下:很抱歉,我不知道安卓浏览器是否提供这种详细级别的信息。 - Joel Mueller
这是一个对于Web应用程序非常重要的问题,而不是网站。原生的Android应用程序也知道方向。为什么Web应用程序不能呢? - Federico Elles
我认为只有纵向和横向的知识是重要的,不关心它是否颠倒等。我关心设计在设备上是宽还是窄。用户需要时会自己翻转设备。我在iOS设备上玩过很多需要我旋转硬件的游戏,我也会这样做。即使我的不到两岁的儿子也可以自动完成此操作。所以这个问题并不是真正的问题。当然,如果我们知道设备的方向,那就太好了,但浏览器仍然在设备顶部显示“最重要的信息”。 - BerggreenDK
显示剩余6条评论

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

它也支持桌面浏览器,但它总是返回相同的值。

4
这个事件主要是为了访问动作传感器,虽然我想它也可以用来检测方向变化。 - René
在我的Android Galaxy S2手机上,股票浏览器和Dolphin浏览器不支持,但是在移动版Firefox中运行良好。 - Eduardo

3

我遇到了同样的问题。我正在使用Phonegap和Jquery Mobile来开发Android设备上的应用程序。 为了正确调整大小,我不得不设置一个超时:

$(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 = $(window).width(); var screenHeight = $(window).height(); if(screenWidth > screenHeight) { doSomething(); } - math0ne
这是我在一款糟糕的Android平板电脑上的解决方案。window.onresize、attachevent和addeventlistener在多个事件(resize、onresize、orientationchange、deviceorientation)上均失败了。只有Jquery $(window).on() 起作用。 - Lego

2

您可以尝试这个解决方案,它与所有浏览器兼容。

以下是 orientationchange 兼容性图片: compatibility 因此,我编写了一个 orientaionchange polyfill,它基于 @media 属性修复了 orientationchange 实用程序库——orientationchange-fix

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

1
另一个需要注意的问题是 - 一些Android平板电脑(我相信是摩托罗拉Xoom和一款低端的Elonex,可能还有其他型号)将它们的加速度计设置为在横屏模式下window.orientation == 0,而不是竖屏!

0
值得注意的是,在我的Epic 4G Touch上,我必须先设置webview使用WebChromeClient,然后才能使任何javascript android调用起作用。
webView.setWebChromeClient(new WebChromeClient());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接