Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter Device orientation for single page on iOS

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?

like image 876
NullPointer Avatar asked Oct 24 '18 23:10

NullPointer


People also ask

How do I change the orientation of one page in flutter?

Set the orientation in flutter First, you have to import the services package. import 'package:flutter/services. dart'; Next, you can set orientation by setting the value to setPreferredOrientations method in SystemChrome class.

How do you get the device orientation in flutter?

In order to determine the Orientation of the screen, we can use the OrientationBuilder Widget. The OrientationBuilder will determine the current Orientation and rebuild when the Orientation changes.


1 Answers

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:

  1. Add the platform channel logic on the iOS side in 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
  1. In the widget/screen which should be landscape oriented define the MethodChannel - https://github.com/vintage/party_flutter/blob/master/lib/ui/screens/game_play.dart#L34
static 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).

  1. When disposing - rotate back to the portrait mode - https://github.com/vintage/party_flutter/blob/master/lib/ui/screens/game_play.dart#L111-L122

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

like image 125
Kamil Rykowski Avatar answered Sep 21 '22 15:09

Kamil Rykowski