【问题标题】:Flutter: How to set and lock screen orientation on-demandFlutter:如何按需设置和锁定屏幕方向
【发布时间】:2018-10-23 15:01:23
【问题描述】:

在我的一个颤动页面上,我需要将屏幕设置为横向模式并将其锁定,这样它就不能旋转到纵向模式,而只能在一页上。因此需要一种方法来即时启用此功能。有人知道怎么做吗?

我希望它向左或向右旋转横向,而不是进入纵向模式。

【问题讨论】:

    标签: flutter screen-orientation device-orientation


    【解决方案1】:

    首先导入服务包:

    import 'package:flutter/services.dart';

    这将使您可以访问SystemChrome 类,"Controls specific aspects of the operating system's graphical interface and how it interacts with the application."

    当您加载 Widget 时,请执行以下操作:

    @override
    void initState(){
      super.initState();
      SystemChrome.setPreferredOrientations([
          DeviceOrientation.landscapeRight,
          DeviceOrientation.landscapeLeft,
      ]);
    }
    

    然后当我离开页面时,像这样恢复正常:

    @override
    dispose(){
      SystemChrome.setPreferredOrientations([
        DeviceOrientation.landscapeRight,
        DeviceOrientation.landscapeLeft,
        DeviceOrientation.portraitUp,
        DeviceOrientation.portraitDown,
      ]);
      super.dispose();
    }
    

    【讨论】:

    • 但似乎仅适用于 android github.com/flutter/flutter/issues/20124
    • 哦,我没有意识到。很有可能,我只在安卓上测试过。
    • 没关系,平台频道github.com/flutter/flutter/issues/13238#issuecomment-435958221可以解决,我想很快就会解决
    • 仅指定此错误已在几个月前解决,此解决方案现在也适用于 iOS
    • 据我所知,在 dispose 方法中设置首选方向并不是一个好主意。如果您导航到另一条路线并打算返回,则不会调用 dispose 方法。
    【解决方案2】:

    我会使用一个简单的 mixin纵向锁定手机。以下解决方案将整个应用程序锁定为纵向将特定屏幕 设置为纵向,同时保持旋转。

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/services.dart';
    
    /// Forces portrait-only mode application-wide
    /// Use this Mixin on the main app widget i.e. app.dart
    /// Flutter's 'App' has to extend Stateless widget.
    ///
    /// Call `super.build(context)` in the main build() method
    /// to enable portrait only mode
    mixin PortraitModeMixin on StatelessWidget {
      @override
      Widget build(BuildContext context) {
        _portraitModeOnly();
        return null;
      }
    }
    
    /// Forces portrait-only mode on a specific screen
    /// Use this Mixin in the specific screen you want to
    /// block to portrait only mode.
    ///
    /// Call `super.build(context)` in the State's build() method
    /// and `super.dispose();` in the State's dispose() method
    mixin PortraitStatefulModeMixin<T extends StatefulWidget> on State<T> {
      @override
      Widget build(BuildContext context) {
        _portraitModeOnly();
        return null;
      }
    
      @override
      void dispose() {
        _enableRotation();
      }
    }
    
    /// blocks rotation; sets orientation to: portrait
    void _portraitModeOnly() {
      SystemChrome.setPreferredOrientations([
        DeviceOrientation.portraitUp,
        DeviceOrientation.portraitDown,
      ]);
    }
    
    void _enableRotation() {
      SystemChrome.setPreferredOrientations([
        DeviceOrientation.portraitUp,
        DeviceOrientation.portraitDown,
        DeviceOrientation.landscapeLeft,
        DeviceOrientation.landscapeRight,
      ]);
    }
    

    在整个应用程序中阻止旋转在主 App 小部件中实现 PortraitModeMixin。记得在Widget build(BuildContext context)方法中调用super.build(context)

    /// Main App widget
    class App extends StatelessWidget with PortraitModeMixin {
      const App();
    
      @override
      Widget build(BuildContext context) {
        super.build(context);
        return CupertinoApp(
          title: 'Flutter Demo',
          theme: CupertinoThemeData(),
          home: Text("Block screen rotation example"),
        );
      }
    }
    

    在特定屏幕中阻止旋转在特定屏幕的状态下实现PortraitStatefulModeMixin&lt;SampleScreen&gt;。记得在 State 的 build() 方法中调用 super.build(context),在 dispose() 方法中调用 super.dispose()。如果您的屏幕是 StatelessWidget - 只需重复应用程序的解决方案(上一个示例),即使用 PortraitModeMixin

    /// Specific screen
    class SampleScreen extends StatefulWidget {
      SampleScreen() : super();
    
      @override
      State<StatefulWidget> createState() => _SampleScreenState();
    }
    
    class _SampleScreenState extends State<SampleScreen>
        with PortraitStatefulModeMixin<SampleScreen> {
      @override
      Widget build(BuildContext context) {
        super.build(context);
        return Text("Flutter - Block screen rotation example");
      }
    
      @override
      void dispose() {
         super.dispose();
      }
    }
    

    从 Dart 2.1 开始使用这种语法的 Mixins

    【讨论】:

    • 我已经尝试过你的 mixin 类 - 无状态版本工作得很好,但是一旦我的 statefull 类调用它的处理方法,statefull 就会抛出异常。请注意,我在课堂上打电话给super.dispose()。以下是错误:I/flutter (29686):在最终确定小部件树时引发以下断言:I/flutter (29686):_MultiPlayerAcceptPageState.dispose 未能调用 super.dispose。 I/flutter (29686): dispose() 实现必须始终调用其超类的 dispose() 方法,以确保所有 I/flutter (29686): 小部件使用的资源都被完全释放。
    • 有状态版本的相同异常。你解决了这个问题吗?
    • 解决了!如果您使用 Android Studio,则可以清楚地检测到这一点。它说dispose() 被注释为@mustCallSuper。这意味着您需要在 mixin 函数本身中添加 super.dispose()
    【解决方案3】:
    void main() {
      WidgetsFlutterBinding.ensureInitialized();
      SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown])
        .then((_) {
          runApp(new MyApp());
        });
    }
    

    【讨论】:

    • 虽然此代码可能会为问题提供解决方案,但最好添加有关其工作原理/方式的上下文。这可以帮助未来的用户学习并将这些知识应用到他们自己的代码中。在解释代码时,您也可能会以赞成票的形式从用户那里获得积极的反馈。
    【解决方案4】:

    首先,将整个应用方向锁定为纵向模式。

    //Do this in main.dart
    SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
      .then((_) {
    runApp(MyApp());
    });
    

    其次,转到要更改方向的特定屏幕。

    @override
    void initState() {
    super.initState();
    
    SystemChrome.setPreferredOrientations([
      DeviceOrientation.portraitUp,
      DeviceOrientation.landscapeRight,
      DeviceOrientation.landscapeLeft
    ]);
    

    }

    @override
    void dispose() {
    SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
    _interstitialAd.dispose();
    super.dispose();
    }
    

    要使用 SystemChrome,您必须添加 'package:flutter/services.dart'

    【讨论】:

    • 无状态小部件怎么办?
    • 您需要一个有状态的小部件来访问生命周期方法。
    【解决方案5】:

    有时由于有关方向的信息为空,它无法工作。 您可以像这样简单地使用它:

    import services.dart
    
    
    void main() {
        SystemChrome.setPreferredOrientations(
        [DeviceOrientation.portraitUp]
         )
            .then((_) {
              runApp(new MyApp());
            });
        }
    

    // 启动应用后等待设置屏幕方向 -> 然后锁定方向

    【讨论】:

      【解决方案6】:

      导入 services.dart 包并添加以下代码以将设备方向锁定为纵向模式:

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

      【讨论】:

      • WidgetsFlutterBinding.ensureInitialized(); 使这个解决方案对我有用。好收获!
      【解决方案7】:

      对 iOS 很重要

      • 在 info.plist 文件中启用方向。例如

      步骤

      • 在 main.dart 文件中设置方向。就我而言,我的应用程序只支持纵向,除了一个屏幕,所以我需要在第一时间设置纵向模式。举例
      SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp,DeviceOrientation.portraitDown,]);
      
      • 在需要旋转的屏幕中添加以下代码。
        void initState() {
          super.initState();
          SystemChrome.setPreferredOrientations([
            DeviceOrientation.landscapeRight,
            DeviceOrientation.landscapeLeft,
          ]);
        }
        @override
        dispose(){
           SystemChrome.setPreferredOrientations([
              DeviceOrientation.portraitUp,
              DeviceOrientation.portraitDown,
            ]);
          super.dispose();
        }
      

      【讨论】:

        【解决方案8】:

        import services.dart 和你的 void main 函数应该是这样的:

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

        【讨论】:

          【解决方案9】:

          在整个应用中锁定屏幕方向的简单方法

          • import 'package:flutter/services.dart'; 添加到main.dart 文件的开头。

          • MyApp 类的Widget 构建区域中创建SystemChrome.setPreferredOrientations(); 方法以禁用屏幕旋转,就在return 部分之前。

          • 在方法的参数中使用[DeviceOrientation.&lt;orientation-type&gt;] 指定方向。

          使用以下之一代替&lt;orientation-type&gt;

          1. portraitUp
          2. portraitDown
          3. landscapeLeft
          4. landscapeRight

          示例代码:

          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(
                  appBar: AppBar(
                  title: Text("Screen Orientation"),
                  ),
                  body: Container(
                  ),
                ),
              );
            }
          }
          

          【讨论】:

            【解决方案10】:

            您可以为此 https://pub.dev/packages/orientation_helper 使用orientation_helper。它的主要目标是为应用中的每个屏幕设置方向。

            【讨论】:

              【解决方案11】:

              对于喜欢使用钩子的人

              import 'package:flutter/services.dart';
              import 'package:flutter_hooks/flutter_hooks.dart';
              
              useOrientation(List<DeviceOrientation> orientations) {
                useEffect(
                  () {
                    SystemChrome.setPreferredOrientations(orientations);
                    return () {
                      SystemChrome.setPreferredOrientations([
                        DeviceOrientation.portraitUp,
                        DeviceOrientation.portraitDown,
                        DeviceOrientation.landscapeLeft,
                        DeviceOrientation.landscapeRight,
                      ]);
                    };
                  },
                );
              }
              

              像这样使用它:

              class MyWidget extends HookWidget {
                void build(BuildContext context) {
              
                  useOrientation([DeviceOrientation.portraitUp]);
              
                  return Container();
                }
              }
              

              【讨论】:

                【解决方案12】:

                在颤振中设置首选方向。

                // import this package
                import 'package:flutter/services.dart';
                
                // Lock the orientation to Portrait Only
                WidgetsFlutterBinding.ensureInitialized();
                SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
                      .then((value) => runApp(MyApp()));
                

                您还可以在setPreferredOrientations 列表中添加首选方向,例如[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]

                以下是您可以设置的方向:

                /// If the device shows its boot logo in portrait, then the boot logo is shown
                  /// in [portraitUp]. Otherwise, the device shows its boot logo in landscape
                  /// and this orientation is obtained by rotating the device 90 degrees
                  /// clockwise from its boot orientation.
                  portraitUp,
                
                  /// The orientation that is 90 degrees clockwise from [portraitUp].
                  ///
                  /// If the device shows its boot logo in landscape, then the boot logo is
                  /// shown in [landscapeLeft].
                  landscapeLeft,
                
                  /// The orientation that is 180 degrees from [portraitUp].
                  portraitDown,
                
                  /// The orientation that is 90 degrees counterclockwise from [portraitUp].
                  landscapeRight,
                

                参考:https://greymag.medium.com/flutter-orientation-lock-portrait-only-c98910ebd769

                【讨论】:

                  【解决方案13】:

                  在主文件夹的AndroidManifest文件中activity标签设置android:screenOrientation = "portrait"

                  <activity android:windowSoftInputMode="adjustResize" android:screenOrientation = "portrait">
                  

                  【讨论】:

                    猜你喜欢
                    • 2011-09-29
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-08-03
                    • 2014-01-13
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-11-10
                    • 1970-01-01
                    相关资源
                    最近更新 更多