【问题标题】:Flutter: how to prevent device orientation changes and force portrait?Flutter:如何防止设备方向改变和强制纵向?
【发布时间】:2018-08-31 06:45:01
【问题描述】:

我想阻止我的应用程序更改其方向并强制布局坚持“纵向”。

在 main.dart 中,我放了:

void main(){
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
    DeviceOrientation.portraitDown
  ]);
  runApp(new MyApp());
}

但是当我使用 Android 模拟器旋转按钮时,布局“遵循”新的设备方向...

我该如何解决这个问题?

谢谢

【问题讨论】:

  • 假设你导入了'package:flutter/services.dart',那么可能是bug:github.com/flutter/flutter/issues/13238
  • 不知道为什么会发生这种情况。我尝试在模拟器和我自己的设备上运行您的代码,它运行良好。
  • SystemChrome.setPreferredOrientations 异步返回,所以似乎runApp 应该包含在then 中。

标签: flutter


【解决方案1】:

导入import 'package:flutter/services.dart';

然后你在你的main.dart 文件和你的 main 方法中包含下面的代码行,如下所示:

WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitDown,
    DeviceOrientation.portraitUp,
  ]);

runApp(myApp());

【讨论】:

    【解决方案2】:

    输入WidgetsFlutterBinding.ensureInitialized() 否则在构建时会出错。

    import 'package:flutter/services.dart';
    
        void main() async => {
              WidgetsFlutterBinding.ensureInitialized();
              await SystemChrome.setPreferredOrientations(
                  [DeviceOrientation.portraitUp],
              ); // To turn off landscape mode
              runApp(MainApp());
            };
    

    【讨论】:

      【解决方案3】:

      对于 android 有两种选择

      1.写在main上

          main() {
            WidgetsFlutterBinding.ensureInitialized();
            SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
                .then((_) {
              runApp(
                child: MyApp(),
              );
            });
      }
      

      2.在 AndroidManifest.xml 文件上本地设置

      iOS 也有两种选择

      1.来自info.plist

      将此行添加到您的 info.plist 文件中

      <array>
          <string>UIInterfaceOrientationPortrait</string>
      </array>
      

      2.来自亚军 从 Xcode 上的 iOS 文件夹中打开 Runner.xcworkspace。单击 Runner 而不是 Pod。您可以在 General>Deployment Info 上找到此选项。只是检查你想要什么

      【讨论】:

        【解决方案4】:

        这个方法很简单->

        SystemChrome.setPreferredOrientations(
              [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
        

        【讨论】:

          【解决方案5】:

          要使SystemChrome.setPreferredOrientations 在 iPad 上工作,请在 Xcode 项目编辑器中启用“需要全屏”,或者只需在项目文件夹的 /ios/Runner/Info.plist 中添加以下行。

          <key>UIRequiresFullScreen</key>
          <true/>
          

          【讨论】:

            【解决方案6】:

            在 iOS 情况下可以启用requires fullscreen 选项。

            void main() async {
                  WidgetsFlutterBinding.ensureInitialized();
                  SystemChrome.setPreferredOrientations([
                    DeviceOrientation.landscapeRight,
                    DeviceOrientation.landscapeLeft,
                  ]).then((_) {
                    runApp(MediaQuery(
                        data: MediaQueryData(),
                        child:
                            MaterialApp(debugShowCheckedModeBanner: false, home: LoginPage())));
                  });
                }
            

            【讨论】:

              【解决方案7】:

              对于人们来说,他们现在正在阅读这个问题。 我找到的最简单的方法,它适用于 android 和 ios 设备。

               void main() {
                WidgetsFlutterBinding.ensureInitialized();
                SystemChrome.setPreferredOrientations(
                  [
                    DeviceOrientation.portraitUp,
                    DeviceOrientation.portraitDown,
                  ],
                ).then((val) {
                  runApp(YourAppName());
                });
              }
              

              【讨论】:

                【解决方案8】:

                这个解决方案在两个不同的 Android 项目中对我有用。不能保证它也适用于 iOS。我已经阅读了所有以前的答案,我认为最好和最简单的解决方案是这样做:

                安卓:

                这样您就可以避免所有可能与您的代码混淆的“await”、“async”和“then”

                /// this is in main.dart
                
                main(){
                  WidgetsFlutterBinding.ensureInitialized();
                
                  runApp(
                    MaterialApp(
                      initialRoute: '/root',
                      routes: {
                        '/root': (context) => MyApp(),
                      },
                      title: "Your App Title",
                    ),
                  );
                }
                
                class MyApp extends StatelessWidget {
                  @override
                  Widget build(BuildContext context) {
                    /// ENFORCE DEVICE ORIENTATION PORTRAIT ONLY
                    SystemChrome.setPreferredOrientations([
                      DeviceOrientation.portraitUp,
                      DeviceOrientation.portraitDown
                    ]);
                
                    /// RUN THE APP
                    return MaterialApp(
                      home: HomeScreen(),
                    );
                  }
                }
                

                iOS:

                我认为this answer's update 是 iOS 的最佳选择。

                !!免责声明! 我做了一些研究,显然,here 的文档特别说:

                setPreferredOrientations method Limitations:
                
                "This setting will only be respected on iPad if multitasking is disabled."
                

                Here 是如何从 XCode 禁用多任务处理(也就是打开“需要全屏”选项)

                iOS 的另一个可能的修复方法

                您也可以试试this one。我没有亲自尝试过,因为我的 PC 上没有 iPad 或 XCode,但值得一试

                【讨论】:

                  【解决方案9】:

                  如果您从 xcode 界面编辑此内容,则不会针对 ipad 进行更改。对于 ipad 部分,您必须从 android studio 编辑 info.plist 文件。你可以在数组列表中看到像“~ ipad”这样的东西。 info.plist 中有两个部分,您必须为 iphone 和 ipad 手动编辑它。

                  【讨论】:

                    【解决方案10】:

                    只需在 main.dart 文件中添加以下代码行即可。

                    SystemChrome.setPreferredOrientations([
                      DeviceOrientation.portraitUp,
                    ]);
                    

                    记得导入 services.dart 文件。下面给出一个例子!

                    import 'package:flutter/material.dart';
                    import 'package:flutter/services.dart';
                    
                    void main() {
                        runApp(MyApp());
                    }
                    
                    
                    class MyApp extends StatelessWidget {
                         @override
                         Widget build(BuildContext context) {
                    
                          SystemChrome.setPreferredOrientations([
                            DeviceOrientation.portraitUp,
                          ]);
                    
                          return MaterialApp(
                            home: Scaffold(
                              body: Center(child: Text("A Flutter Example!")),
                         ),
                       );
                      }
                    }
                    

                    【讨论】:

                      【解决方案11】:

                      以下是flutter团队的官方示例。 https://github.com/flutter/samples/blob/master/veggieseasons/lib/main.dart

                      import 'package:flutter/services.dart' show DeviceOrientation, SystemChrome;
                      
                      void main() {
                          WidgetsFlutterBinding.ensureInitialized();
                          SystemChrome.setPreferredOrientations([
                              DeviceOrientation.portraitUp,
                              DeviceOrientation.portraitDown,
                          ]);
                          runApp(HomeScreen());
                      }
                      

                      【讨论】:

                        【解决方案12】:

                        试试

                         void main() async {
                              WidgetsFlutterBinding.ensureInitialized();
                              await SystemChrome.setPreferredOrientations(
                                  [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); 
                            
                              runApp(MyApp());
                         }
                        

                        您还可以在 android manifest 和 ios info.plist 文件中更改屏幕方向设置。

                        【讨论】:

                          【解决方案13】:

                          对于新的颤振版本以及设置preferred Orientation,我们需要添加一个额外的行,即

                           WidgetsFlutterBinding.ensureInitialized();
                          

                          所以工作代码是 -

                          import 'package:flutter/services.dart';
                              void main() {
                                    WidgetsFlutterBinding.ensureInitialized();
                                    SystemChrome.setPreferredOrientations([
                                      DeviceOrientation.portraitUp,
                                      DeviceOrientation.portraitDown
                                    ]);
                                    runApp(MyApp());
                                  }
                          

                          【讨论】:

                            【解决方案14】:

                            打开 android/app/src/main/AndroidManifest.xml 并在 MainActivity 中添加以下行:

                            android:screenOrientation="portrait"
                            

                            如果你有这个:

                            <activity
                                    android:name=".MainActivity"
                                    android:launchMode="singleTop"
                                    android:theme="@style/LaunchTheme"
                                    android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
                                    android:hardwareAccelerated="true"
                                    android:windowSoftInputMode="adjustResize">
                            

                            你应该得到这样的结果:

                            <activity
                                    android:name=".MainActivity"
                                    android:launchMode="singleTop"
                                    android:theme="@style/LaunchTheme"
                                    android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
                                    android:hardwareAccelerated="true"
                                    android:screenOrientation="portrait"
                                    android:windowSoftInputMode="adjustResize">
                            

                            这适用于 Android。在 iOS 上,您必须从 Xcode 页面更改:https://i.stack.imgur.com/hswoe.png(正如 Hejazi 所说)

                            【讨论】:

                            • 谢谢,记住 configChanges “orientation” 后“portrait”的顺序很重要。
                            【解决方案15】:

                            iOS:

                            调用SystemChrome.setPreferredOrientations() 对我不起作用,我必须更改Xcode project 中的Device Orientation,如下所示:

                            安卓:

                            为文件android/app/src/main/AndroidManifest.xml 中的主要活动设置screenOrientation 属性为portrait,如下所示:

                            【讨论】:

                            • 我遇到了同样的问题,你是在 iPad 上运行的吗?我只在 iPad 上测试过,这似乎是个问题:github.com/flutter/flutter/issues/27235
                            • android:此属性是在 API 级别 24 中添加的。
                            • 我使用 screenOrientation,因为 Android 的 API 级别 8。 @BloodLoss ,我想你在文档上读过它,但是关于 resizeableActivity 属性。再次检查链接。 ^^
                            • 这在 Flutter 2.5 上完美运行,除了我隐藏的 Android 状态栏已经返回。
                            • @Boy 你应该在 ipad 的 info.plist 上更改这个配置 UISupportedInterfaceOrientations~ipadUIInterfaceOrientationPortrait
                            【解决方案16】:

                            首先在 ma​​in.dart 文件中导入这个

                            import 'package:flutter/services.dart';
                            

                            然后不要复制粘贴,而是查看(记住)并在 ma​​in.dart 文件中写入以下代码

                            纵向模式下强制:

                            void main() {
                              SystemChrome.setPreferredOrientations(
                                  [DeviceOrientation.portraitUp,DeviceOrientation.portraitDown])
                                  .then((_) => runApp(MyApp()),
                              );
                            

                            横向模式下强制:

                               void main() {
                                  SystemChrome.setPreferredOrientations(
                                      [DeviceOrientation.landscapeLeft,DeviceOrientation.landscapeRight])
                                      .then((_) => runApp(MyApp()),
                                  );
                            

                            【讨论】:

                            • 谢谢提醒大家不要盲目复制粘贴
                            • 我明白你为什么要求不要复制粘贴...结尾 } 不见了...我复制粘贴... :)
                            【解决方案17】:

                            @boeledi,如果你想“锁定”设备方向并且不允许它随着用户旋转手机而改变,这很容易设置如下,

                            // This did not work as requirement
                            void main() {
                              SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
                              runApp(new MyApp());
                            }
                            

                            你必须等到 setPreferredOrientations 完成然后 启动应用程序

                            // This will works always for lock screen Orientation.
                            void main() {
                              WidgetsFlutterBinding.ensureInitialized();
                              SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
                                .then((_) {
                                  runApp(new MyApp());
                                });
                            }
                            

                            【讨论】:

                            • 编译时有时会报错,应该使用原生解决方案。按照 Abeer Iqbal 的建议,将 'android:screenOrientation="portrait"' 添加到 AndroidManifest 上的 MainActivity 对我在 Android 上有效。
                            【解决方案18】:

                            导入package:flutter/services.dart,然后

                            SystemChrome.setPreferredOrientations 放入Widget build() 方法中。

                            例子:

                              class MyApp extends StatelessWidget {
                                @override
                                Widget build(BuildContext context) {
                                  SystemChrome.setPreferredOrientations([
                                    DeviceOrientation.portraitUp,
                                    DeviceOrientation.portraitDown,
                                  ]);
                                  return new MaterialApp(...);
                                }
                              }
                            

                            更新

                            此解决方案可能不适用于 2019 年 10 月更新的颤振文档中提到的某些 IOS 设备。

                            他们建议通过像这样在 Info.plist 中设置 UISupportedInterfaceOrientations 来固定方向

                            <array>
                                <string>UIInterfaceOrientationPortrait</string>
                            </array>
                            

                            欲了解更多信息https://github.com/flutter/flutter/issues/27235#issuecomment-508995063

                            【讨论】:

                            • 如果您将 SystemChrome.setPreferredOrientations 放在 main 中,您将收到错误:在绑定初始化之前访问了 ServicesBinding.defaultBinaryMessenger。在构建中插入代码是可行的,因为此时已经初始化了绑定。
                            • 提醒,对于 iOS info.plist,您必须在 UISupportedInterfaceOrientations~ipad 下为 iPad 设置它
                            • 我用SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.bottom]); 隐藏了Android 任务栏,并添加它使它再次出现一会儿,然后当我点击某些东西进行导航时它消失了。这是设计使然吗?我将上面的 sn-p 嵌套在 void initState() 中,用于我想隐藏 Android 任务栏的任何页面,而您的 sn-p 在构建主运​​行的顶级屏幕时。
                            【解决方案19】:

                            setPreferredOrientation 返回一个Future&lt;void&gt;,所以它是异步的。最易读的方法是将main定义为异步:

                            Future<void> main() async {
                              await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
                              return runApp(new MyApp());
                            }
                            

                            【讨论】:

                            • 我强烈反对。 await 是一种无处不在的编程模式,存在于多种语言中,很清楚什么是表达性的。 then 创建嵌套级别。如果你有三四个延续,then 确实开始变得非常难以阅读。
                            • .then 可以链接而不是嵌套,因为它需要 FutureOr。这让我可以使用更实用的方法,更易读、更优雅。例如,我可以通过链接“thens”来使用表达式主体而不是括号主体。
                            • 编译时有时会报错,应该使用原生解决方案。按照 Abeer Iqbal 的建议,将 'android:screenOrientation="portrait"' 添加到 AndroidManifest 上的 MainActivity 对我在 Android 上有效。
                            • 如果您遇到错误:“未处理的异常:在初始化绑定之前访问了 ServicesBinding.defaultBinaryMessenger。”尝试使用此修复:stackoverflow.com/questions/57689492/…
                            【解决方案20】:

                            “setPreferredOrientations”方法返回一个 Future 对象。 根据文档,Future 代表将来某处可用的一些值。这就是为什么您应该等到它可用,然后继续使用该应用程序。因此,应该使用“then”方法,根据定义,“注册回调以在 Future 完成时调用”。因此,您应该使用以下代码:

                              void main() {
                              SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) {
                                  runApp(new App());
                                });
                               }
                            

                            另外,必须导入以下文件:

                            'package:flutter/services.dart'

                            【讨论】:

                            • 我可以确认这是可行的。但是当函数没有参数时,使用 whenComplete() 而不是 then()。
                            猜你喜欢
                            • 2020-05-11
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2013-10-08
                            相关资源
                            最近更新 更多