正确防止Flex移动应用程序中的屏幕方向更改

4

有人能在Flex SDK 4.6中正确使用吗?

这是一个简短的片段:

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark" 
        addedToStage="onAddedToStage(event)"
        title="Title">
    <fx:Script>
        <![CDATA[  
            private function onAddedToStage(event:Event):void { 
                if (stage.autoOrients) {
                    stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGING, orientationChanging, false, 0, true);
                }
            }

            private function orientationChanging(event:StageOrientationEvent):void {
                if (event.afterOrientation == StageOrientation.DEFAULT || event.afterOrientation == StageOrientation.UPSIDE_DOWN) {
                    event.preventDefault(); 
                }     
            } 
        ]]>
    </fx:Script>
</s:View>

我想要实现的是在横屏模式下支持两种方向,所以如果用户将设备旋转180度,屏幕也应该旋转。但是当用户将设备旋转到其中一种纵向方向时,不应有任何动作。相反,在纵向方向上,我看到导航器操作栏的宽度发生变化,有时内容也会变化。所以显然仅仅阻止事件是不够的。我正在使用Adobe建议的“官方”方式,但问题是它并不能很好地工作。诚然,舞台没有改变,但似乎导航器中仍然有某些触发事件,因为你可以看到操作栏的宽度在变化。
在处理程序方法中明确设置布局边界为固定宽度后,我取得了一些成功-这可以防止更改操作栏宽度,但这只是一个临时解决方案-如果视图受到过渡或其他重绘的影响,它将重新以错误的大小呈现。好像下面有东西告诉它处于纵向模式,尽管我试图阻止它。
在你提出一些愚蠢的想法,比如“autoOrient = false”之前,请不要。显然这不是解决这个问题的方法。很明显这是Flex SDK的一个错误-有人找到了修复它或稳定的解决方法吗?
编辑:显然,其他人也遇到了类似的问题:
- http://forums.adobe.com/message/3969531(主题是关于其他事情,但请阅读magic robots 的评论)
- http://forums.adobe.com/message/4130972

这很奇怪,因为这正是我在我的应用程序中使用的,而且它非常有效。你使用的SDK版本是什么?编辑:好的,抱歉,刚刚意识到这在你问题的第一行!那就是我使用的版本,所以我完全没有任何想法。你尝试在你的应用程序类中执行它了吗(我不知道为什么会改变任何东西,但这是我能想到的唯一一件事) - Exort
你确定吗?你能创建新的flex移动项目,在视图中使用我的代码,编译并查看吗(即使在调试器中也可以看到,不必将其放在设备上)?你能粘贴出你代码中相关片段吗?我的例子非常简单,没有额外的代码、没有皮肤等,但它明显无法正常工作 - 所以我很难相信它对你起作用了? - rattkin
是的,我刚刚用你的代码替换了我的代码,在iPad上可以运行。虽然我没有监视我的操作栏宽度,但它仍然停留在原地。我将侦听器直接添加到了我的ViewNavigatorApplication的addedToStage上。 - Exort
我也在主应用程序文件中尝试过了,但仍然无法工作。当您使用调试器菜单旋转时,在调试模拟器中明显可见 - 舞台不会改变,但操作栏的宽度会更改,就好像它处于纵向模式下一样。我的应用程序在aspectRatio = landscape模式下启动(在xml中定义)。您是否使用带有SDK 4.6的FB 4.6?Windows还是Mac OS? - rattkin
好的,我做了一些测试,是的,在模拟器上和(有时?)在设备上操作栏大小确实会改变。 我对此一无所知,但不幸的是我没有时间再进行调查。 抱歉:( FYI:在Windows上使用FB和Flex 4.6(我有FB的预发布版本,但这不应该有任何影响) - Exort
2个回答

6

我不确定这是否是正确的解决方案,在经过了很多努力后,我找到了这个稳定的解决方案:

private function onAddedToStage(event:Event):void { 
    if (stage.autoOrients) {
        stage.removeEventListener(StageOrientationEvent.ORIENTATION_CHANGING, orientationChanging);
        stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGING, orientationChanging, false, 100, true);
    }
}      

private function orientationChanging(event:StageOrientationEvent):void {
    event.stopImmediatePropagation();
    if (event.afterOrientation == StageOrientation.DEFAULT || event.afterOrientation == StageOrientation.UPSIDE_DOWN) {
        event.preventDefault(); 
    }   
}  

首先要注意的是在移动应用程序中,addedToStage事件会触发几次(2-3次)。我不知道为什么,我的代码中没有addChild,显然。也许AIR运行时会做一些其他的事情。因此,为了避免添加不必要数量的处理器,常见的技巧是先删除处理器——如果这样的处理器尚未注册,它将不起作用,但如果已经注册,它将被移除,从而保持处理器计数为1。
第二件事是事件的优先级——它不能在0上工作,它必须设置为某个大的值,以在AIR运行时之前启动。
最后一件事——event.stopImmediatePropagation()——现在,我们是第一个处理该事件的人,我们无法防止在这种特定情况下进一步向上发送此事件。
这些结合起来使方向预防完美地工作——对我来说,横向和反向横向(rotated_left、rotated_right)都可以工作和过渡,而纵向模式根本不会影响视图。
现在,这里存在危险——您可能希望在退出视图(在过渡动画结束、视图停用或其他情况下)时删除侦听器,因为stopImmediatePropagation将防止在应用程序的其他部分处理事件。
我希望Adobe(或实际上是Apache)会更加密切地关注这个问题并跟踪我的解决方案。
编辑:
这个解决方案还存在一个问题,即如果应用程序在设备处于默认或倒置的方向时启动,则应用程序将处于纵向模式。
为了解决这个问题,在addedToStage处理器中更改长宽比。
   if(Stage.supportsOrientationChange) {
         stage.setAspectRatio(StageAspectRatio.LANDSCAPE);
    }

进一步调查后,根据我收集的信息,这似乎与stage.width和height有关 - 当我试图在orientationChanging中操纵它们时,有时能够保持正确的行为。无论如何,即使事件被阻止,FlexGlobals.topApplication.aspectRatio也会更改为纵向,但实际上不应该这样。 - rattkin
解决方案完美运行,除了启动时。如果您在DEFAULT或UPSIDE_DOWN设备上启动,则应用程序将处于纵向模式。 - UBIK LOAD PACK
1
谢谢你的解决方案!你节省了我的时间...为什么Adobe的开发人员仍然忽视如此重要的错误和问题:( 没有头绪... - proweb

1

我曾经遇到过你遇到的同样问题。我想我终于找到了解决方案。这是我所做的:

<s:TabbedViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
...blahblahblah...
width="1024"/>

protected function tabbedviewnavigatorapplication2_applicationCompleteHandler(event:FlexEvent):void {
    stage.autoOrients=true;
    preventOrient();
} 

private function preventOrient():void { 
    if (stage.autoOrients) {
        stage.removeEventListener(StageOrientationEvent.ORIENTATION_CHANGING, orientationChanging);
    stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGING, orientationChanging, false, 100, true);
    }
}

private function orientationChanging(event:StageOrientationEvent):void {
    if(event.afterOrientation == StageOrientation.DEFAULT || event.afterOrientation == StageOrientation.UPSIDE_DOWN || event.afterOrientation == StageOrientation.UNKNOWN) {
        event.preventDefault(); 
    }
}

值得注意的是,在应用程序完成处理程序中,我将stage.autoOrients设置为true,因为在app.xml文件中,我将其设置为false,因为有一个闪屏,不希望用户在此期间重新定向屏幕。实际上,我唯一做的不同之处就是考虑了StageOrientation.UNKNOWN并防止它可能会发生的任何事情,在主mxml文件中将宽度设置为1024(针对iPad屏幕,其他平板设备可能不同),并删除了stopimmediatepropagation。希望这可以帮助到您。

2
说实话,你并没有自己想出解决方案,只是抄袭了我的。这没关系,但请不要扭曲事实 :) - rattkin
在运行时更改stage.autoOrients仍然可能会产生一些奇怪的结果(不久之前它是只读属性),我不建议这样做(我只是修改了预加载程序以防止旋转)。此外,我一直在尝试手动设置舞台的宽度/高度,如前所述,但这也并非始终正确,实际上是相当不灵活的解决方案。在我的测试中,我从未遇到过StageOrientation.UNKNOWN,这就是为什么它不在我的示例中的原因。 - rattkin

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