如何在iOS上使用Phonegap正确检测设备方向变化?

182

我在查找JQTouch参考资料时发现了下面这段方向测试代码。它在移动Safari的iOS模拟器上可以正常工作,但在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;
  }
}

12个回答

298

这是我的工作:

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年5月更新:window.orientation是一个已被弃用的功能,大多数浏览器根据MDN的说法都不支持它。 orientationchange事件与window.orientation相关联,因此可能不应该使用。


3
这是本次讨论中唯一适用于我的解决方案 :) +1 - Atadj
10
我会把屏幕旋转时的函数延迟执行一段时间,代码如下:window.onorientationchange = function() { setTimeout(functionName, 0); }; - Kirk Strobeck
11
感兴趣,你为什么使用setTimeout,Kirk? - backdesk
10
注意!这是设备特定的 - 度数是指与设备标准方向的差异。换句话说,如果平板电脑设计为横向使用,则90表示它处于纵向模式。为了解决这个问题,我最初检查窗口的高度和宽度来存储方向,并使用orientationchange来更新方向,以防出现变化。 - benallansmith
15
此外,我发现orientationchange事件在宽度和高度改变之前就被触发了,因此需要稍微延迟一下来使用宽度和高度正确地检测方向。为此,我会存储当前的方向,当检测到变化时,我会在50毫秒的间隔内检查方向变化,最多进行250毫秒。一旦发现差异,我就会相应地更新页面。在我的Nexus 5手机上,它通常会在150毫秒后检测出宽度与高度的差异。 - benallansmith
显示剩余14条评论

24

我使用 window.onresize = function(){ checkOrientation(); } 而在 checkOrientation 函数中,可以使用 window.orientation 或检查主体宽度的方法, 但是最通用的方法是使用 "window.onresize",至少在我测试过的大多数移动和桌面浏览器中都适用。


1
这是一个很好的观点。如果你正在使用面向Web的技术进行开发,这种方法可以让你更容易地在浏览器中进行调试和测试,而不需要每次部署/模拟。 - Matt Ray
2
这样做一点也不好...因为当键盘出现时,它会改变大小(而且这不是唯一的情况)。所以绝对不能这样做! - HellBaby
2
@HellBaby 当键盘出现时,该函数将被调用,但是,根据您用于方向检测的方法,它将检测到方向未发生变化,就像使用window.orientation一样。因此,我仍然坚持我的答案。 - hndcrftd
1
@MattRay,你可以使用最新的开发工具包轻松测试方向变化,这些工具包能够模拟这种设备行为。 - kontur
1
当iPad Air的方向发生变化时,window.onresize()不会被触发。 - GreySage
显示剩余2条评论

17
if (window.matchMedia("(orientation: portrait)").matches) {
   // you're in PORTRAIT mode
}

if (window.matchMedia("(orientation: landscape)").matches) {
  // you're in LANDSCAPE mode
}

1
你可以将它附加到“resize”事件上。然而,如果我没记错的话,这些查询在键盘弹出时不会正确工作。 - adi518

14

我对iOS和Phonegap都很新,但是通过添加事件监听器,我成功地完成了这个任务。我也使用了你提到的示例,但是无法使其工作。但是以下方法似乎能够解决问题:

// 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 中搜索术语“orientation”,或许能找到一些有用的信息。

例如,我曾读到一个用于检测方向的示例 Pie Guy: (游戏, js 文件)。它类似于您发布的代码,但我像您一样无法使其正常工作。

需要注意的是,虽然事件监听器对我来说有效,但这可能不是最佳方法。到目前为止,这是我找到的唯一有效方法,但我不知道是否有更好、更简单的方法。


更新:已修复上面的代码,现在可以正常工作。


10

虽然问题仅涉及PhoneGap和iOS使用,并且已经得到回答,但我可以为JS在2019年检测屏幕方向的更广泛问题添加一些要点:

  1. window.orientation 属性已被弃用,并不受Android浏览器支持。有一个提供更多有关方向信息的新属性- screen.orientation。但它仍处于实验阶段,并不受iOS Safari支持。因此,为了获得最佳结果,您可能需要结合这两个属性使用: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
谢谢,你真的帮了我大忙!我先尝试了cordova插件和current-device,但是你说得没错,自己构建真的超级简单。我已经制作成指令并完成了今天的工作。 - yogibimbi

6

在处理 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)
  });
}

5
我相信正确的答案已经被发布并接受,但我自己也遇到了一些问题,其他人在这里也提到了。在某些平台上,例如窗口尺寸(window.innerWidth,window.innerHeight)和window.orientation属性等各种属性在"orientationchange"事件触发时可能不会被更新。很多时候,在"orientationchange"事件触发后的几毫秒内,window.orientation属性是未定义的(至少在iOS的Chrome中是如此)。我发现处理这个问题的最佳方法是:
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,请随意进行。
谢谢!希望这可以帮到你!

初步测试中,我发现了一个问题:我顺时针旋转了几次,但是警报显示“横向方向:180度”,尽管我的设备实际上是竖向方向。 - Kalnode

3

以下是我所做的:

window.addEventListener('orientationchange', doOnOrientationChange);

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

2
我发现了一个代码,可以检测设备是否处于横屏状态,如果是则添加一个闪屏页面提示“请改变方向查看网站”。该代码适用于iOS、安卓和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">本网站不适合横屏浏览,请将您的设备旋转至竖屏状态。</div> </div>


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

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