Reputation: 1329
I want to show a single page in my Flutter application in landscape mode. Every other screen should be shown in portrait mode.
I found this code snippet:
In my main.dart
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]).then((_) {
runApp(new IHGApp());
});
This starts the app in portrait mode. So I have the screen I want to show in landscape mode and this is the code I used there:
@override
void initState() {
super.initState();
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);
}
@override
void dispose() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
super.dispose();
}
This works on Android.
On iOS it seems there is no way to force landscape mode for a single page.
https://github.com/flutter/flutter/issues/13238
On this article I found the issue for this problem. sroddy mentioned how to fix the problem.
"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"];
How can I implement this in my app?
Upvotes: 8
Views: 5406
Reputation: 1
this is working fine in Android but not in ios
Upvotes: 0
Reputation: 188
In my case, I find it better to restore default values inside a WillPopScope widget instead of dispose, because you'll get a smoother pop transition (but may not be valid for all cases)
Upvotes: 0
Reputation: 12345
In my case, I made it without channels. Only Flutter code.
1st step. Change possible device orientations in the Xcode
2nd step. In the root widget of your app add a list of default orientations. Usually, it's before the Material app widget.
@override
void initState() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
super.initState();
}
So, now, our app has only one orientation.
3rd step. On the screen that should have other orientations (for example, in my case, full-screen videos) add
@override
void initState() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);
super.initState();
}
@override
void dispose() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
super.dispose();
}
Upvotes: 2
Reputation: 1459
I've had the exact same requirement in one of my apps. Lucky you - the whole project is open sourced! Let's get it done:
ios/Runner/AppDelegate.m
- https://github.com/vintage/party_flutter/blob/27b11fc46755d8901f02c3b439b294ca9005277a/ios/Runner/AppDelegate.m#L8-L23#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
FlutterMethodChannel* rotationChannel = [FlutterMethodChannel
methodChannelWithName:@"zgadula/orientation"
binaryMessenger:controller];
[rotationChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
if ([@"setLandscape" isEqualToString:call.method]) {
[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeRight) forKey:@"orientation"];
}
else if ([@"setPortrait" isEqualToString:call.method]) {
[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationPortrait) forKey:@"orientation"];
}
else {
result(FlutterMethodNotImplemented);
}
}];
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
MethodChannel
- https://github.com/vintage/party_flutter/blob/master/lib/ui/screens/game_play.dart#L34static const _rotationChannel = const MethodChannel('zgadula/orientation');
3.initState
should trigger the rotation to landscape - https://github.com/vintage/party_flutter/blob/master/lib/ui/screens/game_play.dart#L71-L78
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
]);
// TODO: Remove it when fixed in Flutter
// https://github.com/flutter/flutter/issues/13238
try {
_rotationChannel.invokeMethod('setLandscape');
} catch (error) {}
The try-catch is to handle Android part (no such channel, as it works as expected without it).
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
// TODO: Remove it when fixed in Flutter
// https://github.com/flutter/flutter/issues/13238
try {
_rotationChannel.invokeMethod('setPortrait');
} catch (error) {}
if (_rotateSubscription != null) {
_rotateSubscription.cancel();
}
Feel free to change zgadula/orientation
to something which would match your project better :)
Upvotes: 3