352

I would like to prevent my application from changing its orientation and force the layout to stick to "portrait".

In the main.dart, I put:

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

but when I use the Android Simulator rotate buttons, the layout "follows" the new device orientation...

How could I solve this?

Thanks

4
  • 6
    Assuming you imported 'package:flutter/services.dart', then maybe it's a bug: github.com/flutter/flutter/issues/13238
    – Brian Kung
    Mar 22, 2018 at 0:14
  • Not sure why this happens to you. I tried running your code on an emulator and also my own device and it works fine. Mar 22, 2018 at 6:28
  • 3
    SystemChrome.setPreferredOrientations returns asynchronously, so seems like runApp should be enclosed in a then.
    – Ken
    Mar 14, 2020 at 20:03
  • @Ken is correct. Make main() async and put await in front of SystemChrome... Apr 15, 2023 at 2:35

24 Answers 24

424

Import package:flutter/services.dart, then

Put the SystemChrome.setPreferredOrientations inside the Widget build() method.

Example:

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

Update

This solution mightn't work for some IOS devices as mentioned in the updated flutter documentation on Oct 2019.

They Advise to fixed the orientation by setting UISupportedInterfaceOrientations in Info.plist like this

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

For more information https://github.com/flutter/flutter/issues/27235#issuecomment-508995063

3
  • 7
    If you put SystemChrome.setPreferredOrientations in main you will get the error: ServicesBinding.defaultBinaryMessenger was accessed before the binding was initialized. Inserting the code in build works because bindings have been initialized at this point. Aug 14, 2020 at 16:23
  • 3
    Reminder that for iOS info.plist, you have to set it for iPad as well under <key>UISupportedInterfaceOrientations~ipad</key>
    – RyanNa
    Mar 8, 2021 at 14:45
  • I hid the Android task bar with SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.bottom]); and adding this makes it appear again for a moment and then it goes away when I tap something to navigate. Is this by design? I have the above snippet nested in void initState() for whichever page I want to hide Android task bar and your snippet in build of my top level screen that main runs. Sep 28, 2021 at 23:43
167

@boeledi, If you want to “lock” the device orientation and not allow it to change as the user rotates their phone, this was easily set as below,

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

You have to wait until setPreferredOrientations is done and then start the app

// This will always work for lock screen Orientation.
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
  ]);
  runApp(new MyApp());
}
1
  • 4
    It sometimes throws an error while compiling, you should use native solutions. Adding 'android:screenOrientation="portrait"' to MainActivity on AndroidManifest as Abeer Iqbal's suggests worked for me on Android.
    – Tincho825
    Mar 11, 2020 at 17:00
132

iOS:

Calling SystemChrome.setPreferredOrientations() doesn't work for me, and I had to change the Device Orientation in the Xcode project as following:

enter image description here

Android:

Set the screenOrientation attribute to portrait for the main activity in the file android/app/src/main/AndroidManifest.xml as following:

enter image description here

5
  • I had the same problem, did you run it on an iPad? I only tested on an iPad and this seems to be an issue: github.com/flutter/flutter/issues/27235
    – Boy
    Oct 27, 2019 at 6:27
  • android: This attribute was added in API level 24.
    – BIS Tech
    Apr 25, 2020 at 20:27
  • 2
    I use screenOrientation since API level 8 for Android. @BloodLoss , I think you read it on the docs, but about resizeableActivity attribute. Check the link again. ^^ Jun 14, 2020 at 20:10
  • This worked perfectly on Flutter 2.5 except the Android status bar I was hiding has returned. Sep 28, 2021 at 22:37
  • 1
    @Boy you should change this configuration on info.plist for ipad <key>UISupportedInterfaceOrientations~ipad</key> <array> <string>UIInterfaceOrientationPortrait</string> </array> Oct 27, 2021 at 15:44
70

Open android/app/src/main/AndroidManifest.xml and add the following line in the MainActivity:

android:screenOrientation="portrait"

If you have this:

<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">

You should end up with something like this:

<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">

This works for Android. On iOS, you will have to change this from the Xcode page: https://i.stack.imgur.com/hswoe.png (as Hejazi said)

2
  • 3
    thanks ,REMEMBER the order of "portrait" after the configChanges "orientation" does matter.
    – MR_AMDEV
    Apr 4, 2020 at 19:05
  • 1
    cleanest way so far
    – Johan
    May 14, 2022 at 3:53
60

Put the WidgetsFlutterBinding.ensureInitialized() else you will get an error while building.

import 'package:flutter/services.dart';

    void main() async => {
          WidgetsFlutterBinding.ensureInitialized();
          await SystemChrome.setPreferredOrientations(
              [DeviceOrientation.portraitUp],
          ); // To turn off landscape mode
          runApp(MainApp());
        };
28

The 'setPreferredOrientations' method returns a Future object. Per documentation a Future represents some value that will be available somewhere in future. That's why you shall wait until it's available and then move on with the application. Hence, there shall be used 'then' method, which, per definition, "registers callbacks to be called when the Future completes". Hence, you shall use this code:

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

Also, the following file must be imported:

'package:flutter/services.dart'

1
  • I can confirm this works. But use whenComplete() instead of then(), when the function got no param. Jun 12, 2020 at 9:56
19

First of all import this in main.dart file

import 'package:flutter/services.dart';

Then don't copy paste rather see(remember) and write below code in main.dart file

To force in portrait mode:

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

To force in landscape mode:

void main() {
  SystemChrome.setPreferredOrientations(
      [DeviceOrientation.landscapeLeft,DeviceOrientation.landscapeRight])
      .then((_) => runApp(MyApp()),
  );
}
2
  • 2
    Thank you for reminding people not to copy-paste blindly
    – Ryan
    May 24, 2020 at 4:39
  • 4
    I see why you asked NOT to copy paste ... the ending } is missing... I copy pasted... :) May 31, 2020 at 11:21
13

Flutter orientation lock: portrait only

In Flutter we have SystemChrome.setPreferredOrientation() (see documentation) to define preferred orientation. Exactly this method you can find in all those articles about setup orientation in Flutter. Let’s see how we can use it:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  // We need to call it manually,
  // because we going to call setPreferredOrientations()
  // before the runApp() call
  WidgetsFlutterBinding.ensureInitialized();
  
  // Than we setup preferred orientations,
  // and only after it finished we run our app
  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
      .then((value) => runApp(MyApp()));
}

iOS

Open project in Xcode (ios/Runner.xcworkspace), choose Runner in the project navigator, select Target Runner and on Tab General in section Deployment Info we can setup Device Orientation:

enter image description here

Also, we can do it manually without opening Xcode at all — just edit ios/Runner/Info.plist. Open it as a text file, find key UISupportedInterfaceOrientation and leave only desired values:

<key>UISupportedInterfaceOrientations</key>
<array>
    <string>UIInterfaceOrientationPortrait</string>
</array>

Android

To define orientation for Android we need to edit ApplicationManifest. Open android/app/src/main/AndroidManifest.xml and add an attribute screenOrientation for a main activity:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.orientation_lock_example">
    <application ...>
        <activity
            android:name=".MainActivity"
            android:screenOrientation="portrait"
            ...
            />
            ... 
        </activity>
        ... 
    </application>
</manifest>

And that’s all. Here is the repository with an example app:

Hope this was helpful.

9

For people, that they are reading this question now. The easiest way that I found and it worked on both android & ios devices.

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

Import import 'package:flutter/services.dart';

Then you include the line of code below in your main.dart file, and in your main method like so:

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

runApp(myApp());

6

Just add the following line of code in the main.dart file.

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

and remember to import services.dart file. An example is given below!

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!")),
     ),
   );
  }
}
6

You have two options for for android

1. Write for on main

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

2. Set from natively on AndroidManifest.xml file enter image description here

You have also two option for iOS

1. from info.plist

add this line to your info.plist file

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

2. from Runner open your Runner.xcworkspace from iOS folder on your Xcode. Click on Runner not Pods. You can find this option on General>Deployment Info. just check what you want enter image description here

5

setPreferredOrientation returns a Future<void>, so it is asynchronous. The most readable approach is to define main as asynchronous:

Future<void> main() async {
  await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
  return runApp(new MyApp());
}
4
  • 3
    I strongly disagree. await is a ubiquitous programming pattern that is present in multiple languages, and it's very clear what expressive. then creates levels of nesting. If you have three or four continuations, then starts to become very difficult to read indeed.
    – Rob Lyndon
    Jan 24, 2020 at 15:05
  • .then can be chained instead of nesting, as it expects a FutureOr. This allows me to use a more functional approach, which is more readable and elegant. For example, I can use expression body instead of bracketed body by chaining the "thens". Jan 27, 2020 at 8:49
  • It sometimes throws an error while compiling, you should use native solutions. Adding 'android:screenOrientation="portrait"' to MainActivity on AndroidManifest as Abeer Iqbal's suggests worked for me on Android.
    – Tincho825
    Mar 11, 2020 at 17:01
  • If you are facing an error: "Unhandled Exception: ServicesBinding.defaultBinaryMessenger was accessed before the binding was initialized." try using this fix: stackoverflow.com/questions/57689492/… Aug 8, 2020 at 18:42
4

Below is the official example of the flutter team. 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());
}
4

To force portrait in iPad, you also have to modify key UISupportedInterfaceOrientations~ipad in ios/Runner/Info.plist:

    <key>UISupportedInterfaceOrientations~ipad</key>
    <array>
            <string>UIInterfaceOrientationPortrait</string>
            <string>UIInterfaceOrientationPortraitUpsideDown</string>
    </array>

This can also be done through XCode.

Above will work locally. In order to upload to the App Store through XCode, you also have the add the following to Info.plist. This can also be done by checking "Requires full screen" under Target->General->Deployment Info.

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

Otherwise you'll get an error while uploading.

2

Try

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

You can also change the screen orientation settings in the android manifest and ios info.plist file.

2

It's possible to enable the requires fullscreen option in iOS case.

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

enter image description here

1

As of new flutter versions along with setting the preferred Orientation we need to add one extra line i.e

 WidgetsFlutterBinding.ensureInitialized();

So working code for this is -

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

This solution has worked for me on two different projects for Android. Can't guarantee it will work for iOS too. I've read all the previous answers and I think the best and simplest solution is to do it like this:

Android:

This way you avoid all the "await"s, "async"s and "then"s that might mess around with your code

/// 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:

I think this answer's update is your best bet for iOS.

!! DISCLAIMER !! I did a little bit of research and apparently, the documentation here specifically says:

setPreferredOrientations method Limitations:

"This setting will only be respected on iPad if multitasking is disabled."

Here is how you can disable multitasking (AKA turn on "Requires Full Screen" option) from XCode

Another possible fix for iOS

You might also try this one out. I haven't tried it personally, since I don't have an iPad or XCode on my PC, but it's worth a shot

0

If you are editing this from the xcode interface, it will not be changed for ipad. For the ipad section, you must edit the info.plist file from the android studio. You can see in the array list like that "~ ipad". There are two sections available in info.plist, you have to manually edit it for both iphone and ipad.

0

To make SystemChrome.setPreferredOrientations to work on iPad, enable "Requires full screen" in Xcode project editor or simply add the following lines in /ios/Runner/Info.plist in your project folder.

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

This is simple way ->

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

If your camera screen is still rotate in some case (iPhone 14 Plus, my case), after setting

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

App Startup dart file then add below code where you initiate camera controller.

await cameraController.lockCaptureOrientation(DeviceOrientation.portraitUp);
0

One scenario where SystemChrome.setPreferredOrientations() won't work (even on iPhone) is where - for whatever reason - you have put your FlutterViewController inside a UINavigationController.

In this case, as is expected iOS behaviour, it is the UINavigationController which is responsible for handling orientation changes, not the FlutterViewController (which is why SystemChrome.setPreferredOrientations() won't work).

To force a given orientation in this case, you should therefore subclass the UINavigationController and specify the orientations you wish to support:

class MyNavigationController: UINavigationController {
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask { .portrait }
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.