Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SystemChrome.setPreferredOrientations does not force the device to the given orientations until the device is physically rotated #13238

Closed
sroddy opened this issue Nov 29, 2017 · 75 comments
Labels
a: annoyance Repeatedly frustrating issues with non-experimental functionality c: API break Backwards-incompatible API changes customer: crowd Affects or could affect many people, though not necessarily a specific customer. engine flutter/engine repository. See also e: labels. platform-ios iOS applications specifically

Comments

@sroddy
Copy link
Contributor

sroddy commented Nov 29, 2017

Steps to Reproduce

Running on iOS 10/11

Start an app in portrait mode and invoke:

SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp ]);

then invoke

SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft ]);

Notice that neither the device neither the simulator automatically rotate until you physically rotate the device (and does not rotate at all if the device rotation trigger is locked).

This happens because calling +[UIViewController attemptRotationToDeviceOrientation] here https://github.com/flutter/engine/blob/master/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm#L703 is unfortunately not enough.

I workarounded the issue creating a small platform channel that invokes this code for switching to portrait right before the call to setPreferredOrientations:

[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationPortrait) forKey:@"orientation"];

And the counterpart code for switching to landscape

[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeLeft) forKey:@"orientation"];

This solved my issue.
I think the current behaviour under iOS is bugged, moreover because my expected behaviour is what is currently happening on the Android counterpart without the need of any workaroud.

I know that the proposed way to fix it looks bad (using key-value coding on a read-only property), but if you search around the Internet, it seems to be the most reliable (and possibly only) way to handle this thing when you have just one view / view controller.

@sroddy
Copy link
Contributor Author

sroddy commented Nov 29, 2017

cc @chinmaygarde

@chinmaygarde
Copy link
Member

I am not sure why this is not working for you. From my reading of the documentation on -[UIViewController supportedInterfaceOrientations] and -[UIViewController shouldAutorotate], the responses that the FlutterViewController makes to UIKit seem to be correct (assuming that the view controller is the top most view controller in the view controller hierarchy).

Have you checked whether the supported interface orientations are present in the application's Info.plist and that the application or its delegate is not giving conflicting replies in the -[UIApplicationDelegate application:supportedInterfaceOrientationsForWindow:] method?

@chinmaygarde
Copy link
Member

cc @cbracken

@sroddy
Copy link
Contributor Author

sroddy commented Nov 30, 2017

I know they seem right. Unfortunately they don't work.

https://stackoverflow.com/a/19125466

A call to attemptRotationToDeviceOrientation only rotates the orientation of the interface, if and only if, the device itself has been rotated.

I've been fighting in the past with this issue in the last 1 year and half and so far the only consistent way I've found to deal with this is to check the real device orientation and force it to one of the supported ones if unsupported.

@sroddy
Copy link
Contributor Author

sroddy commented Dec 4, 2017

@chinmaygarde @cbracken you can see here a basic example demonstrating the issue:

Notice that:

  • If the previous device orientation was one of the supported ones (e.g. you keep the device in portraitUp mode or you lock the screen rotation), pressing the button won't produce any visible effect.
  • if you set the orientation to landscapeLeft, the orientation will change as soon as you physically rotate the device (cmd-right-arrow in iOS simulator). if you now keep the device in landscapeLeft, tapping the button won't produce any visible effect.
  • If you rotate the device in one of the two unsupported orientations (landscapeRight or portraitUp), tapping the button will produce the expected behaviour, causing the interface to rotate accordingly to the setting any time you tap on the button.
  • If you run the same code in Android, the behaviour is as (I guess) expected.

@btastic
Copy link

btastic commented Feb 24, 2018

We just noticed that when the device was in landscape and then the flutter app is opened with

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

The app will open in landscaped regardless of this setting.

@Hixie Hixie added platform-ios iOS applications specifically engine flutter/engine repository. See also e: labels. labels May 30, 2018
@Hixie Hixie added this to the Goals milestone May 30, 2018
@CaiJingLong
Copy link
Contributor

CaiJingLong commented Jun 8, 2018

In iPad, this method doesn't seem to be implemented.
When I rotated iPad, flutter's UI rotated.

flutter doctor -v

[✓] Flutter (Channel master, v0.4.5-pre.85, on Mac OS X 10.12.6 16G29, locale zh-Hans-CN)
    • Flutter version 0.4.5-pre.85 at /Users/cai/fluttersdk/flutter
    • Framework revision 677df7c351 (2 weeks ago), 2018-05-24 16:33:46 -0700
    • Engine revision abd74ed5ed
    • Dart version 2.0.0-dev.55.0.flutter-97b6c2e09d

[!] Android toolchain - develop for Android devices (Android SDK 26.0.2)
    • Android SDK at /Users/cai/Library/Android/sdk
    • Android NDK at /Users/cai/Library/Android/sdk/ndk-bundle
    • Platform android-27, build-tools 26.0.2
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b01)
    ! Some Android licenses not accepted.  To resolve this, run: flutter doctor --android-licenses

[✓] iOS toolchain - develop for iOS devices (Xcode 9.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 9.2, Build version 9C40b
    • ios-deploy 1.9.2
    • CocoaPods version 1.5.0

[✓] Android Studio (version 3.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 23.1.2
    • Dart plugin version 171.4424
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b01)

[✓] IntelliJ IDEA Ultimate Edition (version 2018.1.4)
    • IntelliJ at /Users/cai/Applications/JetBrains Toolbox/IntelliJ IDEA Ultimate.app
    • Flutter plugin version 24.0.2
    • Dart plugin version 181.4203.498

[✓] VS Code (version 1.23.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Dart Code extension version 2.12.1

[✓] Connected devices (4 available)
    • PRO 5               • 192.168.2.2:5555                         • android-arm64 • Android 5.1 (API 22)
    • iPad mini2          • 58366e2a63aae6f85e6e806039316c27faa52868 • ios           • iOS 10.0.2
    • iPhone 8 Plus       • 8595BEDC-42FA-4B3E-8461-2AEC3D1B6272     • ios           • iOS 11.2 (simulator)
    • iPad Pro (9.7-inch) • E24A8FEF-1F44-4B3F-9FCB-2960D7CABB1C     • ios           • iOS 11.2 (simulator)


@miguelpruivo
Copy link

+1

1 similar comment
@crnaosa
Copy link

crnaosa commented Aug 31, 2018

+1

@zoechi
Copy link
Contributor

zoechi commented Aug 31, 2018

@miguelpruivo @crnaosa
Using "add reaction" on the initial comment would increase priority while +1 comments are rather pointless and cause lots of people to get notified for no reason.
If you want to get notified just click the "Subscribe" button to the right.

@lennartschoch
Copy link

I am experiencing the same issue both with the iOS emulator (iPad Pro 9.7, iOS 12) and a physical device (iPad Air 2, iOS 11). I implemented the setPreferredOrientations method inside the main function, but there is no effect noticeable. This is a huge problem when developing with user interfaces which are designed to only work in either portrait or landscape mode, not both. Can we get an update on this?

@albo1337
Copy link

@sroddy Could you please share your solution? I'm facing the same issue and have no idea how to fix this on iOS. It seems that you fixed it.

@lennartschoch
Copy link

lennartschoch commented Oct 25, 2018

@albo1337 Not an ideal solution, but if you just want to get your whole app locked to a certain orientation, you can specify that inside the Info.plist file inside ios/Runner:

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

Just remove the orientations that you do not support.

Edit: Of course, this doesn't help if you need to lock specific views of your app, but might be helpful for anyone who stumbles upon this thread and wants their whole app locked ;)

@albo1337
Copy link

@lennartschoch the problem is, I need the landscape mode only for one screen and the portrait mode for every other screen... Your solution does not help me with my current problem, but thank you a lot for your help!

@miguelpruivo
Copy link

@albo1337 that’s exactly what I need as well.

@jaumard
Copy link
Contributor

jaumard commented Nov 2, 2018

@albo1337 I'm in the same case, I need the device in landscape for one screen and all the other in portrait. I have the same issue as you, you need to rotate the device for the UI to follow :(
Works great on Android, but not on iOS

@sroddy
Copy link
Contributor Author

sroddy commented Nov 5, 2018

@albo1337 You basically need to create a custom platform channel and use it to force the desired orientation right after setting the preferred one. In Dart:

SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft ]);
_rotationChannel.invokeMethod('setLandscape');

in iOS code:

[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeLeft) forKey:@"orientation"];

@GaryQian
Copy link
Contributor

GaryQian commented Dec 6, 2018

cc @chinmaygarde Does this new information bring anything to light on this issue?

@eseidelGoogle
Copy link
Contributor

This sounds like it might be an easy fix? Maybe a starter bug for one of the new engine hackers @cbracken?

The implementation of SystemChrome is here:
https://github.com/flutter/engine/search?q=systemChrome&unscoped_q=systemChrome

@jaumard
Copy link
Contributor

jaumard commented Jan 11, 2019

Ha ha @eseidelGoogle ! Easy fix when you know where to do it 😆 I've searched on the source where to do this fix with no luck ^^ thanks for pointing that out !
But for now I'm using @sroddy 's solution and force screen rotation by myself until the fix :)

@eseidelGoogle
Copy link
Contributor

Looks like someone even wrote a medium article about this and how to work around it. :/
https://medium.com/@kr1uz/how-to-restrict-device-orientation-in-flutter-65431cd35113

@eseidelGoogle
Copy link
Contributor

CC @kriuz the author of said article.

@lennartschoch
Copy link

lennartschoch commented Jan 22, 2019

@eseidelGoogle I actually tried exactly that and couldn't get the orientation locked on an iPad Air 2 :/

@eseidelGoogle
Copy link
Contributor

It's hard for me to parse from this issue how much of this could be Flutter itself, vs if the plugins/APIs involved are just not calling the right iOS APIs to implement their desired functionality. Either are probably easy to fix?

@xster might have a guess.

@sroddy
Copy link
Contributor Author

sroddy commented Jan 22, 2019

@eseidelGoogle from my experience the only reliable way to force the orientation when the device itself is not rotated is setting it using key-value coding. It would be quite easy to provide a patch on the engine using this approach. Any other way unfortunately have proven to be unsuccessful.

@timsneath timsneath added customer: crowd Affects or could affect many people, though not necessarily a specific customer. severe: customer critical labels Oct 29, 2019
@Hixie
Copy link
Contributor

Hixie commented Oct 29, 2019

We believe this is fixed in dev. If you were running into this before, can you try flutter channel dev; flutter upgrade and see if you still see this?

@josh-ksr
Copy link
Contributor

@Hixie i don´t think it is fixed in dev as the merge was reverted. There´s a new merge request (flutter/engine#13170) but that´s not merged yet.

@mav2287
Copy link

mav2287 commented Oct 31, 2019

I just tried the Dev channel and it is still not working as expected.

@GaryQian
Copy link
Contributor

@josh-ksr Sorry for the delay, it is merged again!

@GaryQian
Copy link
Contributor

Change is in master again as of 353721a

@elmariocarlos
Copy link

Awesome news! @sroddy @btastic @lukasgit would you test for implementation?

@cbracken cbracken added waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds and removed platform-android Android applications specifically labels Nov 4, 2019
@cbracken
Copy link
Member

cbracken commented Nov 4, 2019

I've removed the platform-android label, since this issue is very embedder-specific and the original issue, workarounds in comments, and fix are all iOS-specific. If people are running into a similar issue on Android, please file an issue and link it here from a comment to help others find it and add a thumbs-up reaction.

Just so @elmariocarlos 's question does't get lost after this comment: @sroddy @btastic @lukasgit I'm closing this issue as fixed now that the patch has landed, but please let us know if you're still seeing this and we'll re-open.

@cbracken cbracken closed this as completed Nov 4, 2019
@kanthi0802
Copy link

Issues still exists in both Andorid and iOS. Below is the Flutter Doctor report

[✓] Flutter (Channel master, v1.10.16-pre.67, on Mac OS X 10.14.1 18B75, locale en-GB)
• Flutter version 1.10.16-pre.67 at /Users/kanthis/Documents/Flutter/flutter
• Framework revision e3742b6 (5 hours ago), 2019-11-06 23:13:17 -0500
• Engine revision c448d39
• Dart version 2.7.0

[!] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
• Android SDK at /Users/kanthis/Library/Android/sdk
• Android NDK location not configured (optional; useful for native profiling support)
• Platform android-28, build-tools 28.0.3
• Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)
! Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses

[!] Xcode - develop for iOS and macOS (Xcode 10.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 10.1, Build version 10B61
✗ Flutter requires a minimum Xcode version of 10.2.0.
Download the latest version or update via the Mac App Store.
• CocoaPods version 1.6.1

[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 3.5)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin version 41.0.2
• Dart plugin version 191.8593
• Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)

[✓] Connected device (3 available)
• Android SDK built for x86 • emulator-5554 • android-x86 • Android 9 (API 28) (emulator)
• Chrome • chrome • web-javascript • Google Chrome 78.0.3904.87
• Web Server • web-server • web-javascript • Flutter Tools

! Doctor found issues in 2 categories.

@cbracken cbracken reopened this Nov 8, 2019
@mofada
Copy link

mofada commented Nov 9, 2019

I tried it, it is ok,

Channel master, v1.10.16-pre.88

@mofada
Copy link

mofada commented Nov 9, 2019

@kanthi0802

@mofada
Copy link

mofada commented Nov 9, 2019

upgrade your flutter and retry

@kanthi0802
Copy link

Not working for me tried with
Flutter (Channel master, v1.10.16-pre.110, on Mac OS X 10.14.1 18B75, locale en-GB).
Should we do anything other than calling
SystemChrome.setPreferredOrientations(
[DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
?

@ztpr0035
Copy link

ztpr0035 commented Nov 11, 2019

@lennartschoch the problem is, I need the landscape mode only for one screen and the portrait mode for every other screen... Your solution does not help me with my current problem, but thank you a lot for your help!

Hello @lennartschoch, I think this will solve your issue , I tried it and it work on both platforms,

return RotatedBox(
quarterTurns: 1,
child: Scaffold(),);

@cbracken
Copy link
Member

Sounds like this is resolved based on other reports.

@lennartschoch please let us know if @ztpr0035's suggestion doesn't work for you.

@mirkopoloni
Copy link

mirkopoloni commented Dec 20, 2019

Working fine on iPhone but still having problems on iPad, am I the only one?

Channel master, v1.13.4-pre.12, on Mac OS X 10.15.1

UPDATE 13 January
I just found out that this can't actually work on iPad without some limitations, it isn't a bug... sorry if I didn't find it out before writing my comment.
As a reference for other people, more infos here:
#27235 (comment)
https://api.flutter.dev/flutter/services/SystemChrome/setPreferredOrientations.html

@ghost
Copy link

ghost commented Jan 9, 2020

Oh man, I'm forced to use v1.9.x due to older phone compatability... Any workaround for that version?

@hawkinsjb1
Copy link

hawkinsjb1 commented Jul 8, 2020

Is the only solution to this really to use a RotatedBox as @ztpr0035 mentioned? This doesn't properly change the screen's size like a native orientation change. I'm having lots of overflow errors trying to use that solution

EDIT: Nevermind orientation is properly getting updated, my WillPopScope wasn't being triggered because I wasn't using maybePop(), duh..

@pisces116
Copy link

Why this issue is not resolved but is marked as resolved

@pedromassangocode pedromassangocode removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Dec 30, 2020
@SaidiAli
Copy link

The issue is closed but I think i can add this just incase. I am just learning flutter and in a lecture by Maximiliano of academind, he points out that for the issue at hand to work you need to add a WidgetFlutterBinding.ensureInitialised().
Like:
WidgetFlutterBinding.ensureInitialised(); SystemChrome.setPrefferedOrientation();

@yubaokang
Copy link

在iPhone上可以正常工作,但在iPad上仍然有问题,我是唯一的一个吗?

Channel master, v1.13.4-pre.12, on Mac OS X 10.15.1

1月13日更新
我刚刚发现,如果没有一些限制,这实际上无法在iPad上运行,这不是bug。...抱歉,如果我在写评论之前没有找到它。
作为其他人的参考,请在此处获取更多信息:
#27235(评论)
https://api.flutter.dev/flutter/services/SystemChrome/setPreferredOrientations.html

then same

@github-actions
Copy link

github-actions bot commented Aug 7, 2021

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 7, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a: annoyance Repeatedly frustrating issues with non-experimental functionality c: API break Backwards-incompatible API changes customer: crowd Affects or could affect many people, though not necessarily a specific customer. engine flutter/engine repository. See also e: labels. platform-ios iOS applications specifically
Projects
None yet
Development

No branches or pull requests