Flutter 控制螢幕旋轉的實現
最近需要做個平板的專案,然後需要直接橫屏,有2種實現方式。
1,隨著螢幕旋轉,佈局自動調整。做橫豎屏適配
2,強制螢幕橫屏,不隨著螢幕去調整
第一種方式這裡就不做說明了。程式碼做適配就可以。 下面說一下第二種實現方式
Flutter 自帶方式
flutter 為我們提供了方法來控制系統的橫豎屏顯示
SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft,DeviceOrientation.landscapeRight,DeviceOrientation.portraitUp,DeviceOrientation.portraitDown ]).then((_) { });
包含的方向型別。 !!!!但是但是但是這個方法只適用於android在iOS上沒有效果,上網查資料有大神封裝的 flutter外掛orientation,flutter外掛auto_orientation 在iOS上都起不到效果,所以打算自己寫一個原生檔案與flutter進行通訊,實現螢幕旋轉。也是筆者在查詢資料之後做的一個整合和解釋說明
iOS端實現螢幕旋轉
建立iOS原生檔案
建立iOS原生檔案來實現互動,首先要建立個原生檔案。命名為FlutterIOSDevicePlugin。 建立檔案
建立一個命名為FlutterIOSDevicePlugin.h 和命名為FlutterIOSDevicePlugin.m檔案,說明一下: FlutterIOSDevicePlugin.h檔案選擇圖片裡面的header File模組建立即可。
建立之後,一起看一下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 */
這個不需要過多說明了看一下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); } } @end
以上是全部的程式碼,其中嘗試了用通知的方式去做螢幕旋轉,後來發現其實沒有那麼麻煩,直接採用的是
[[UIDevice currentDevice] setValue:@(iOSOrientation) forKey:@"orientation"];
方式做的。其中遇到的問題:
問題1:iphone手機上可以正常旋轉,ipad上不行
這個問題主要原因是info。plist檔案裡面的iphone和ipad不一致,且勾選Requires full screen 即可
回到正軌哈
註冊原生外掛檔案
iOS 工程種有個GeneratedPluginRegistrant.m檔案,直接註冊就可以了。 如果你專案引入了其他第三方外掛,也是統一在這個地方註冊的
#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
程式碼中的這個片段是自己寫的外掛註冊的方法,其他的AutoOrientationPlugin,OrientationPlugin是引用第三方外掛自動生成的程式碼。
[FlutterIOSDevicePlugin registerWithRegistrar: [registry registrarForPlugin:@"FlutterIOSDevicePlugin"]];
AppDelegate檔案中的設定
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) } }
其中changeLandscape方法是控制監聽的事件的方法,目前沒什麼用。 主要程式碼是這一段,這個是在發出螢幕旋轉的時候回撥的方法,這裡面設定的是全部的方向都可以。
override func application(_ application: UIApplication,supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return orientationMask; }
問題2:程式不走該方法
具體原因是因為info.plist檔案問題。參考上面設定就沒問題
flutter 原生程式碼使用
這個地方是針對於iOS平臺去做的區別。
MethodChannel _channel = const MethodChannel('flutter_ios_device'); @override void initState() { SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft,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]); }
程式碼不用過多說明了, 有不瞭解的可以留言
問題3: 啟動程式自動旋轉
SystemChrome.setPreferredOrientations需要設定全部內容。不然會預設旋轉。有點小坑,
以上基本上可以實現螢幕旋轉的問題,如果有小夥伴還是不行,可以試一下用iOS原生通知的方式去完成。這個我做的是平板的專案,暫時沒有問題,更多相關Flutter 控制螢幕旋轉內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!