Recently, we need to make a tablet project, and then we need to directly landscape screen. There are two ways to achieve this.

  • 1. The layout adjusts automatically as the screen rotates. Do vertical screen adaptation
  • 2, force the screen landscape, do not adjust with the screen

The first way is not explained here. Code adaptation can be done. Let’s talk about the second implementation

Flutter by itself

The Flutter provides us with a way to control the vertical and horizontal display of the system

 SystemChrome.setPreferredOrientations([
      DeviceOrientation.landscapeLeft,
      DeviceOrientation.landscapeRight,
      DeviceOrientation.portraitUp,
      DeviceOrientation.portraitDown
    ]).then((_) {
    });
Copy the code

Contains the direction type. !!!!!!!!!! This method only works on Android and doesn’t work on iOS. Check the website for information about the orientation of the flutter plugin, and the auto_orientation plugin doesn’t work on iOS. Therefore, I decided to write a native file to communicate with Flutter and realize screen rotation. It is also an integration and explanation made after the author inquires the data

Screen rotation is implemented on iOS

Create iOS native files

To create an iOS native file for interaction, start by creating a native file. Name it FlutterIOSDevicePlugin. Create a fileCreate flutteriosdeviceplugin. h and flutteriosdeviceplugin. m File, flutteriosDeviceplugin. h File, flutteriosDeviceplugin. h File, flutteriosDeviceplugin. h File.

Once created, take a look at the code in FlutteriosDeviceplugin.h

#ifndef FlutterIOSDevicePlugin_h
#define FlutterIOSDevicePlugin_h

#import <Flutter/Flutter.h>

@interface FlutterIOSDevicePlugin : NSObject<FlutterPlugin>
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar flutterViewController:(FlutterViewController*) controller;
- (instancetype)newInstance:(NSObject<FlutterPluginRegistrar>*)registrar flutterViewController:(FlutterViewController*) controller;
@end
#endif /* FlutterIOSDevicePlugin_h */
Copy the code

This doesn’t need much explanation. Take a look at the code for FlutteriosDeviceplugin.m

#import <Foundation/Foundation.h> #import "FlutterIOSDevicePlugin.h" @interface FlutterIOSDevicePlugin () { NSObject<FlutterPluginRegistrar> *_registrar; FlutterViewController *_controller; } @end static NSString* const CHANNEL_NAME = @"flutter_ios_device"; static NSString* const METHOD_CHANGE_ORIENTATION = @"change_screen_orientation"; static NSString* const ORIENTATION_PORTRAIT_UP = @"portraitUp"; static NSString* const ORIENTATION_PORTRAIT_DOWN = @"portraitDown"; static NSString* const ORIENTATION_LANDSCAPE_LEFT = @"landscapeLeft"; static NSString* const ORIENTATION_LANDSCAPE_RIGHT = @"landscapeRight"; @implementation FlutterIOSDevicePlugin + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar { FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:CHANNEL_NAME binaryMessenger:[registrar messenger]]; FlutterIOSDevicePlugin* instance = [[FlutterIOSDevicePlugin alloc] newInstance:registrar flutterViewController:nil]; [registrar addMethodCallDelegate:instance channel:channel]; } + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar flutterViewController:(FlutterViewController*) controller { FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:CHANNEL_NAME binaryMessenger:[registrar messenger]]; FlutterIOSDevicePlugin* instance = [[FlutterIOSDevicePlugin alloc] newInstance:registrar flutterViewController:controller]; [registrar addMethodCallDelegate:instance channel:channel]; } - (instancetype)newInstance:(NSObject<FlutterPluginRegistrar>*)registrar flutterViewController:(FlutterViewController*) controller{ _registrar = registrar; _controller = controller; return self; } - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { if ([METHOD_CHANGE_ORIENTATION isEqualToString:call.method]) { NSArray *arguments = call.arguments; NSString *orientation = arguments[0]; NSNumber *index = [NSNumber numberWithInt: [call.arguments[0] intValue]]; NSInteger iOSOrientation; if ([orientation isEqualToString:ORIENTATION_LANDSCAPE_LEFT]){ iOSOrientation = UIDeviceOrientationLandscapeLeft; }else if([orientation isEqualToString:ORIENTATION_LANDSCAPE_RIGHT]){ iOSOrientation = UIDeviceOrientationLandscapeRight;  }else if ([orientation isEqualToString:ORIENTATION_PORTRAIT_DOWN]){ iOSOrientation = UIDeviceOrientationPortraitUpsideDown; }else{ iOSOrientation = UIDeviceOrientationPortrait; } [[UIDevice currentDevice] setValue:@(iOSOrientation) forKey:@"orientation"]; // [[NSNotificationCenter defaultCenter] postNotificationName:@"FlutterIOSDevicePlugin" object:nil userInfo:@{@"orientationMask": index}]; // [UIViewController attemptRotationToDeviceOrientation]; result(nil); } else { result(FlutterMethodNotImplemented); } } @endCopy the code

The above is all the code, which tried to use the notification way to do the screen rotation, later found that it is not so troublesome, directly used is

[[UIDevice currentDevice] setValue:@(iOSOrientation) forKey:@"orientation"];
Copy the code

Way to do. Problems encountered:

Problem 1: Rotation works on the iPhone, not on the iPad

The main reason for this problem is info. The plist file Requires “Requires Full Screen” and “iPhone” is “Requires Full screen”Back on track

Register the native plug-in file

IOS project of a GeneratedPluginRegistrant. M file, direct registration is ok. If you introduce other third party plug-ins into your project, you should register them in this place as well

#import "GeneratedPluginRegistrant.h"

#if __has_include(<auto_orientation/AutoOrientationPlugin.h>)
#import <auto_orientation/AutoOrientationPlugin.h>
#else
@import auto_orientation;
#endif

#if __has_include(<orientation/OrientationPlugin.h>)
#import <orientation/OrientationPlugin.h>
#else
@import orientation;
#endif
#import "FlutterIOSDevicePlugin.h"

@implementation GeneratedPluginRegistrant

+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
  [AutoOrientationPlugin registerWithRegistrar:[registry registrarForPlugin:@"AutoOrientationPlugin"]];
  [OrientationPlugin registerWithRegistrar:[registry registrarForPlugin:@"OrientationPlugin"]];
//    [registry registrarForPlugin:@"FlutterIOSDevicePlugin"];
   

    [FlutterIOSDevicePlugin registerWithRegistrar: [registry registrarForPlugin:@"FlutterIOSDevicePlugin"]];
}

@end
Copy the code

This fragment in the code is the method of plug-in registration written by myself, and the other AutoOrientationPlugin is the code automatically generated by referencing the third-party plug-in.

[FlutterIOSDevicePlugin registerWithRegistrar: [registry registrarForPlugin:@"FlutterIOSDevicePlugin"]];
Copy the code

Settings in the AppDelegate file

import UIKit import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { var orientationMask: UIInterfaceOrientationMask = .all; override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { NotificationCenter.default.addObserver(self, selector: #selector(changeLandscape(center:)), name:NSNotification.Name(rawValue: "FlutterIOSDevicePlugin"), object: nil) GeneratedPluginRegistrant.register(with: self); return super.application(application, didFinishLaunchingWithOptions: launchOptions) } override func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return orientationMask; } @objc func changeLandscape(center: Notification){ let index: NSNumber = (center.userInfo? ["orientationMask"] ?? 5) as! NSNumber var mask : UIInterfaceOrientationMask = .all switch index { case 0: mask = .portrait break case 1: mask = .landscapeLeft break case 2: mask = .landscapeRight break case 3: mask = .portraitUpsideDown break case 4: mask = .landscape break case 5: mask = .all break case 6: mask = .allButUpsideDown break default: mask = .all break } orientationMask = mask; _ = application(UIApplication.shared, supportedInterfaceOrientationsFor: UIApplication.shared.keyWindow) } }Copy the code

The Changelscape method, which controls the events being listened to, is not currently useful. The main code is this section, which is the callback method when the screen is rotated, which is set to all directions.

    override func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return orientationMask;
    }
Copy the code

Problem 2: The program does not follow this method

The reason is the info.plist file. Refer to the above Settings

Use the Flutter native code

This is where the difference is made for iOS.

MethodChannel _channel = const MethodChannel('flutter_ios_device'); @override void initState() { SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight, DeviceOrientation.portraitUp, DeviceOrientation.portraitDown ]).then((_) { if (Platform.isIOS) { this.changeScreenOrientation(DeviceOrientation.landscapeLeft); }}); super.initState(); } Future<void> changeScreenOrientation(DeviceOrientation orientation) { String o; switch (orientation) { case DeviceOrientation.portraitUp: o = 'portraitUp'; break; case DeviceOrientation.portraitDown: o = 'portraitDown'; break; case DeviceOrientation.landscapeLeft: o = 'landscapeLeft'; break; case DeviceOrientation.landscapeRight: o = 'landscapeRight'; break; } return _channel.invokeMethod('change_screen_orientation', [o]); }Copy the code

Code without too much explanation, do not understand can leave a message

Problem 3: The boot program rotates automatically

SystemChrome. SetPreferredOrientations need to set up all the content. Otherwise it will default to rotation. It’s a little pothole,

The above can basically achieve the screen rotation problem, if some friends still can not, you can try to use iOS native notification to complete. This is a tablet project I do, there is no problem for now, welcome everyone to discuss